Re: Framebuffer Monochrom Glyphs ( was: Re: Atari MiNT Port )
by m0n0
Am Mittwoch, den 29.09.2010, 15:03 +0200 schrieb Rob Kendrick
<rjek(a)netsurf-browser.org>:
> On Wed, Sep 29, 2010 at 02:10:22PM +0200, m0n0 wrote:
> Firstly, don't use monochrome rasterising with FreeType. It's actually
> slower than anti-aliased rendering, because it has to do a second pass
> for drop-out control.
I'm not using monochrom rastering, I know that it is slower ( for
small
glyphs ) :) I just did a quick test because I remembered the topic.
Anyway
maybe it can be usefull when rendering for 256 colors...
> Additionally, when reporting issues, please include information on what
> versions of everything you are using, and what changes you have made
> from that version. Otherwise we cannot help you.
desktop/netsurf.c netsurf_init 142: version '3.0 (Development)'
desktop/netsurf.c netsurf_init 149: NetSurf on <Linux>, node <armdev>,
release <2.6.27-14-generic>, version <#1 SMP Tue Jun 30 19:57:39 UTC
2009>, machine <i686>
libnsfb revision: Revision 10856
framebuffer frontend revision: 10708
Greets,
m
12 years, 12 months
Framebuffer Monochrom Glyphs ( was: Re: Atari MiNT Port )
by m0n0
Hello,
> Am Mo, 31.05.2010, 15:33 schrieb Bernd Roesch:
>> there seem a problem in static bool
>> glyph1(nsfb_t *nsfb,
>>
>> older netsurf work, but newer not.maybe its a endian issue when it work on
>> your Linux build and
>> internal fonts
>> maybe you can confirm this
When using monochrom glyphs with freetype under the
linux-SDL-framebuffer version (little endian), it also gives garbled
glyphs. So there must be an error in the framebuffer font-bitmap
processing.
Greets,
m
12 years, 12 months
Review: treeview-redux [5/7] -- RISC OS frontend changes
by John-Mark Bell
Added files
Index: !NetSurf/Resources/Icons
===================================================================
Index: !NetSurf/Resources/Icons/directory.png
===================================================================
Binary files /dev/null and !NetSurf/Resources/Icons/directory.png differ
Index: !NetSurf/Resources/Icons/content.png
===================================================================
Binary files /dev/null and !NetSurf/Resources/Icons/content.png differ
Index: riscos/sslcert.h
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ riscos/sslcert.h 2010-09-23 22:26:03.000000000 +0100
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2006 Richard Wilson <info(a)tinct.net>
+ * Copyright 2010 Stephen Fryatt <stevef(a)netsurf-browser.org>
+ *
+ * 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/>.
+ */
+
+/** \file
+ * SSL certificate viewer (interface).
+ */
+
+#ifndef _NETSURF_RISCOS_SSLCERT_H_
+#define _NETSURF_RISCOS_SSLCERT_H_
+
+void ro_gui_cert_preinitialise(void);
+void ro_gui_cert_postinitialise(void);
+void ro_gui_cert_open(struct tree *tree, struct node *node);
+
+#endif
+
Index: riscos/hotlist.h
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ riscos/hotlist.h 2010-09-23 22:26:04.000000000 +0100
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2006 Richard Wilson <info(a)tinct.net>
+ * Copyright 2010 Stephen Fryatt <stevef(a)netsurf-browser.org>
+ *
+ * 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/>.
+ */
+
+/** \file
+ * Hotlist (interface).
+ */
+
+#ifndef _NETSURF_RISCOS_HOTLIST_H_
+#define _NETSURF_RISCOS_HOTLIST_H_
+
+void ro_gui_hotlist_preinitialise(void);
+void ro_gui_hotlist_postinitialise(void);
+void ro_gui_hotlist_open(void);
+void ro_gui_hotlist_save(void);
+void ro_gui_hotlist_update_theme(void);
+bool ro_gui_hotlist_check_window(wimp_w window);
+bool ro_gui_hotlist_check_menu(wimp_menu *menu);
+
+#endif
+
Index: riscos/url_suggest.c
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ riscos/url_suggest.c 2010-09-23 22:26:06.000000000 +0100
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2010 Stephen Fryatt <stevef(a)netsurf-browser.org>
+ *
+ * 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/>.
+ */
+
+/** \file
+ * URL Suggestion Menu (implementation).
+ */
+
+#include <assert.h>
+#include "oslib/wimp.h"
+#include "content/content_type.h"
+#include "content/urldb.h"
+#include "riscos/menus.h"
+#include "riscos/url_suggest.h"
+#include "utils/messages.h"
+
+struct url_suggest_item {
+ const char *url; /*< The URL being stored. */
+ unsigned int weight; /*< A weight assigned to the URL. */
+ struct url_suggest_item *next; /*< The next URL in the list. */
+};
+
+static bool url_suggest_callback(const char *url, const struct url_data *data);
+
+static wimp_menu *suggest_menu;
+static int suggest_entries;
+static time_t suggest_time;
+static struct url_suggest_item *suggest_list;
+
+/**
+ * Initialise the URL suggestion menu. A menu block which must be set to
+ * contain URL_SUGGEST_MAX_URLS entries is passed in.
+ *
+ * /param *menu The menu to use as the suggestion menu.
+ * /return true if initialisation was OK; else false.
+ */
+
+bool ro_gui_url_suggest_init(wimp_menu *menu)
+{
+ suggest_menu = menu;
+
+ suggest_menu->title_data.indirected_text.text =
+ (char *) messages_get("URLSuggest");
+ ro_gui_menu_init_structure((wimp_menu *) suggest_menu,
+ URL_SUGGEST_MAX_URLS);
+
+ suggest_entries = 0;
+
+ return true;
+}
+
+
+/**
+ * Builds the URL suggestion menu. This is called by ro_gui_menu_create() when
+ * it is asked to display the url_suggest_menu.
+ *
+ * /return true if the menu has entries; else false.
+ */
+
+bool ro_gui_url_suggest_prepare_menu(void)
+{
+ int i;
+ struct url_suggest_item *list, *next;
+
+ /* Fetch the URLs we want to include from URLdb. */
+
+ suggest_entries = 0;
+ suggest_list = NULL;
+ suggest_time = time(NULL);
+
+ urldb_iterate_entries(url_suggest_callback);
+
+ /* If any menu entries were found, put them into the menu. The list
+ * is in reverse order, last to first, so the menu is filled backwards.
+ * Entries from the list are freed as we go.
+ */
+
+ assert(suggest_entries <= URL_SUGGEST_MAX_URLS);
+
+ if (suggest_entries > 0) {
+ i = suggest_entries;
+
+ list = suggest_list;
+ suggest_list = NULL;
+
+ while (list != NULL && i > 0) {
+ i--;
+
+ suggest_menu->entries[i].menu_flags = 0;
+ suggest_menu->entries[i].data.indirected_text.text =
+ (char *) list->url;
+ suggest_menu->entries[i].data.indirected_text.size =
+ strlen(list->url) + 1;
+
+ next = list->next;
+ free(list);
+ list = next;
+ }
+
+ /* If i hasn't reached 0, then something went wrong -- get
+ * out now!
+ */
+
+ if (i > 0)
+ return false;
+
+ suggest_menu->entries[0].menu_flags |=
+ wimp_MENU_TITLE_INDIRECTED;
+ suggest_menu->entries[suggest_entries - 1].menu_flags |=
+ wimp_MENU_LAST;
+
+ return true;
+ }
+
+ return false;
+}
+
+
+/**
+ * Callback function for urldb_iterate_entries
+ *
+ * \param url URL which matches
+ * \param data Data associated with URL
+ * \return true to continue iteration, false otherwise
+ */
+
+bool url_suggest_callback(const char *url, const struct url_data *data)
+{
+ int count;
+ unsigned int weight;
+ struct url_suggest_item **list, *new, *old;
+
+ /* Ignore unvisited URLs, and those that don't apply to HTML or Text. */
+
+ if (data->visits <= 0 ||(data->type != CONTENT_HTML &&
+ data->type != CONTENT_TEXTPLAIN))
+ return true;
+
+ /* Calculate a weight for the URL. */
+
+ weight = (suggest_time - data->last_visit) / data->visits;
+
+ /* Hunt through those URLs already found to see if we want to add
+ * this one. Smaller weights carry higher priority.
+ *
+ * The list is sorted into reverse order, so that lowest weight
+ * items are nearest the head. Therefore, items are dropped from
+ * the head, making things simpler.
+ */
+
+ list = &suggest_list;
+ count = 0;
+
+ while (*list != NULL && weight < (*list)->weight) {
+ list = &((*list)->next);
+ count++;
+ }
+
+ if (count > 0 || suggest_entries < URL_SUGGEST_MAX_URLS) {
+ new = (struct url_suggest_item *)
+ malloc(sizeof(struct url_suggest_item));
+
+ if (new != NULL) {
+ suggest_entries++;
+ new->url = url;
+ new->weight = weight;
+ new->next = *list;
+
+ *list = new;
+ }
+ }
+
+ /* If adding the URL gave us too many menu items, drop the lowest
+ * priority ones until the list is the right length again.
+ */
+
+ while (suggest_list != NULL && suggest_entries > URL_SUGGEST_MAX_URLS) {
+ old = suggest_list;
+ suggest_list = suggest_list->next;
+ free(old);
+ suggest_entries--;
+ }
+
+ return true;
+}
+
Index: riscos/url_suggest.h
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ riscos/url_suggest.h 2010-09-23 22:26:06.000000000 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010 Stephen Fryatt <stevef(a)netsurf-browser.org>
+ *
+ * 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/>.
+ */
+
+/** \file
+ * URL Suggestion Menu (interface).
+ */
+
+#ifndef _NETSURF_RISCOS_URL_SUGGEST_H_
+#define _NETSURF_RISCOS_URL_SUGGEST_H_
+
+#include "oslib/wimp.h"
+
+#define URL_SUGGEST_MAX_URLS 16
+
+bool ro_gui_url_suggest_init(wimp_menu *menu);
+bool ro_gui_url_suggest_prepare_menu(void);
+
+#endif
+
Changed files
configure/con_home.c | 6
cookies.c | 338 +++++---
cookies.h | 10
dialog.c | 74 -
global_history.c | 524 ++++---------
global_history.h | 12
gui.c | 81 +-
gui.h | 17
help.c | 28
hotlist.c | 526 ++++++-------
menus.c | 678 +++++------------
menus.h | 20
save.c | 14
sslcert.c | 509 +++++-------
textselection.c | 25
theme.c | 28
treeview.c | 2010 ++++++++++++++++++---------------------------------
treeview.h | 49 -
url_complete.c | 6
wimp_event.c | 203 ++++-
wimp_event.h | 22
window.c | 78 +
22 files changed, 2234 insertions(+), 3024 deletions(-)
Index: riscos/dialog.c
===================================================================
--- riscos/dialog.c (revision 10834)
+++ riscos/dialog.c (working copy)
@@ -39,11 +39,14 @@
#include "riscos/dialog.h"
#include "riscos/global_history.h"
#include "riscos/gui.h"
+#include "riscos/hotlist.h"
#include "riscos/menus.h"
#include "riscos/options.h"
#include "riscos/save.h"
+#include "riscos/sslcert.h"
#include "riscos/theme.h"
#include "riscos/url_complete.h"
+#include "riscos/url_suggest.h"
#include "riscos/wimp.h"
#include "riscos/wimp_event.h"
#include "riscos/wimputils.h"
@@ -106,18 +109,6 @@
/* 401 login window */
ro_gui_401login_init();
- /* certificate verification window */
- ro_gui_cert_init();
-
- /* hotlist window */
- ro_gui_hotlist_initialise();
-
- /* global history window */
- ro_gui_global_history_initialise();
-
- /* cookies window */
- ro_gui_cookies_initialise();
-
/* theme installation */
dialog_theme_install = ro_gui_dialog_create("theme_inst");
ro_gui_wimp_event_register_cancel(dialog_theme_install,
@@ -150,24 +141,6 @@
dialog_objinfo = ro_gui_dialog_create("objectinfo");
ro_gui_wimp_event_set_help_prefix(dialog_objinfo, "HelpObjInfo");
- /* hotlist folder editing */
- dialog_folder = ro_gui_dialog_create("new_folder");
- ro_gui_wimp_event_register_text_field(dialog_folder, ICON_FOLDER_NAME);
- ro_gui_wimp_event_register_cancel(dialog_folder, ICON_FOLDER_CANCEL);
- ro_gui_wimp_event_register_ok(dialog_folder, ICON_FOLDER_OK,
- ro_gui_hotlist_dialog_apply);
- ro_gui_wimp_event_set_help_prefix(dialog_folder, "HelpHotFolder");
-
- /* hotlist entry editing */
- dialog_entry = ro_gui_dialog_create("new_entry");
- ro_gui_wimp_event_register_text_field(dialog_entry, ICON_ENTRY_NAME);
- ro_gui_wimp_event_register_menu_gright(dialog_entry, ICON_ENTRY_URL,
- ICON_ENTRY_RECENT, url_suggest_menu);
- ro_gui_wimp_event_register_cancel(dialog_entry, ICON_ENTRY_CANCEL);
- ro_gui_wimp_event_register_ok(dialog_entry, ICON_ENTRY_OK,
- ro_gui_hotlist_dialog_apply);
- ro_gui_wimp_event_set_help_prefix(dialog_entry, "HelpHotEntry");
-
/* save as */
dialog_saveas = ro_gui_saveas_create("saveas");
ro_gui_wimp_event_register_button(dialog_saveas, ICON_SAVE_ICON,
@@ -204,6 +177,22 @@
ro_gui_wimp_event_register_ok(dialog_zoom, ICON_ZOOM_OK,
ro_gui_dialog_zoom_apply);
ro_gui_wimp_event_set_help_prefix(dialog_zoom, "HelpScaleView");
+
+ /* Treeview initialisation has moved to the end, to allow any
+ * associated dialogues to be set up first.
+ */
+
+ /* certificate verification window */
+ ro_gui_cert_preinitialise();
+
+ /* hotlist window */
+ ro_gui_hotlist_preinitialise();
+
+ /* global history window */
+ ro_gui_global_history_preinitialise();
+
+ /* cookies window */
+ ro_gui_cookies_preinitialise();
}
@@ -638,15 +627,25 @@
*/
void ro_gui_dialog_close_persistent(wimp_w parent) {
- int i;
+ int i;
+ wimp_w w;
- /* Check our mappings
- */
+ /* Check our mappings.
+ *
+ * The window handle is copied into w before proceeding, as
+ * ro_gui_dialog_close() will NULL persistent_dialog[i].dialog as
+ * part of the closing process. This would mean that the subsequent
+ * event dispatch would fail. (These events are logged to allow
+ * side effects to be investigated -- this code hasn't worked before).
+ */
for (i = 0; i < MAX_PERSISTENT; i++) {
if (persistent_dialog[i].parent == parent &&
persistent_dialog[i].dialog != NULL) {
- ro_gui_dialog_close(persistent_dialog[i].dialog);
- ro_gui_wimp_event_close_window(persistent_dialog[i].dialog);
+ w = persistent_dialog[i].dialog;
+ ro_gui_dialog_close(w);
+ if (ro_gui_wimp_event_close_window(w))
+ LOG(("Persistent dialog close event: 0x%x",
+ (unsigned) w));
persistent_dialog[i].parent = NULL;
persistent_dialog[i].dialog = NULL;
}
@@ -710,7 +709,6 @@
res = url_normalize(url, &url2);
if (res == URL_FUNC_OK) {
browser_window_create(url2, 0, 0, true, false);
- global_history_add_recent(url2);
free(url2);
return true;
}
@@ -724,10 +722,8 @@
void ro_gui_dialog_prepare_open_url(void)
{
- int suggestions;
ro_gui_set_icon_string(dialog_openurl, ICON_OPENURL_URL, "", true);
- global_history_get_recent(&suggestions);
ro_gui_set_icon_shaded_state(dialog_openurl,
- ICON_OPENURL_MENU, (suggestions <= 0));
+ ICON_OPENURL_MENU, !ro_gui_url_suggest_prepare_menu());
ro_gui_wimp_event_memorise(dialog_openurl);
}
Index: riscos/theme.c
===================================================================
--- riscos/theme.c (revision 10834)
+++ riscos/theme.c (working copy)
@@ -38,8 +38,11 @@
#include "oslib/wimpspriteop.h"
#include "content/content.h"
#include "desktop/gui.h"
+#include "riscos/cookies.h"
#include "riscos/dialog.h"
+#include "riscos/global_history.h"
#include "riscos/gui.h"
+#include "riscos/hotlist.h"
#include "riscos/menus.h"
#include "riscos/options.h"
#include "riscos/theme.h"
@@ -585,9 +588,9 @@
/* apply the theme to all the current windows */
ro_gui_window_update_theme();
- ro_gui_tree_update_theme(hotlist_tree);
- ro_gui_tree_update_theme(global_history_tree);
- ro_gui_tree_update_theme(cookies_tree);
+ ro_gui_cookies_update_theme();
+ ro_gui_global_history_update_theme();
+ ro_gui_hotlist_update_theme();
ro_gui_theme_close(theme_previous, false);
return true;
}
@@ -944,14 +947,16 @@
ro_gui_wimp_event_register_mouse_click(toolbar->toolbar_handle,
ro_gui_toolbar_click);
break;
- case THEME_HOTLIST_TOOLBAR:
- case THEME_HOTLIST_EDIT_TOOLBAR:
- case THEME_HISTORY_TOOLBAR:
- case THEME_HISTORY_EDIT_TOOLBAR:
- case THEME_COOKIES_TOOLBAR:
- case THEME_COOKIES_EDIT_TOOLBAR:
- ro_gui_wimp_event_register_mouse_click(toolbar->toolbar_handle,
- ro_gui_tree_toolbar_click);
+ case THEME_HOTLIST_TOOLBAR:
+ case THEME_HOTLIST_EDIT_TOOLBAR:
+ case THEME_HISTORY_TOOLBAR:
+ case THEME_HISTORY_EDIT_TOOLBAR:
+ case THEME_COOKIES_TOOLBAR:
+ case THEME_COOKIES_EDIT_TOOLBAR:
+ ro_gui_wimp_event_register_mouse_click(toolbar->toolbar_handle,
+ ro_gui_treeview_toolbar_click);
+ break;
+ default:
break;
}
@@ -1322,6 +1327,7 @@
xwimp_force_redraw(toolbar->parent_handle,
0, -16384, 16384, 16384);
}
+
}
/* Reformat the buttons starting with the throbber
Index: riscos/sslcert.c
===================================================================
--- riscos/sslcert.c (revision 10834)
+++ riscos/sslcert.c (working copy)
@@ -1,5 +1,6 @@
/*
* Copyright 2006 John M Bell <jmb202(a)ecs.soton.ac.uk>
+ * Copyright 2010 Stephen Fryatt <stevef(a)netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -32,9 +33,11 @@
#include "content/fetch.h"
#include "content/urldb.h"
#include "desktop/browser.h"
+#include "desktop/sslcert.h"
#include "desktop/gui.h"
#include "desktop/tree.h"
#include "riscos/dialog.h"
+#include "riscos/sslcert.h"
#include "riscos/textarea.h"
#include "riscos/treeview.h"
#include "riscos/wimp.h"
@@ -47,50 +50,36 @@
#define ICON_SSL_REJECT 3
#define ICON_SSL_ACCEPT 4
-#define ICON_CERT_VERSION 3
-#define ICON_CERT_VALID_FROM 5
-#define ICON_CERT_TYPE 7
-#define ICON_CERT_VALID_TO 9
-#define ICON_CERT_SERIAL 11
-#define ICON_CERT_ISSUER 13
-#define ICON_CERT_SUBJECT 15
+static wimp_window *ro_gui_cert_dialog_template;
+static wimp_window *ro_gui_cert_tree_template;
-static wimp_window *dialog_tree_template;
-static wimp_window *dialog_cert_template;
-static wimp_window *dialog_display_template;
-
-struct session_data {
- struct session_cert *certs;
- unsigned long num;
- char *url;
- struct tree *tree;
-
- nserror (*cb)(bool proceed, void *pw);
- void *cbpw;
+struct ro_sslcert
+{
+ wimp_w window;
+ wimp_w pane;
+ ro_treeview *tv;
+ struct sslcert_session_data *data;
};
-struct session_cert {
- char version[16], valid_from[32], valid_to[32], type[8], serial[32];
- char *issuer_t;
- char *subject_t;
- uintptr_t issuer;
- uintptr_t subject;
-};
-static bool ro_gui_cert_click(wimp_pointer *pointer);
-static void ro_gui_cert_close(wimp_w w);
-static bool ro_gui_cert_apply(wimp_w w);
+static void ro_gui_cert_accept(wimp_pointer *pointer);
+static void ro_gui_cert_reject(wimp_pointer *pointer);
+static void ro_gui_cert_close_window(wimp_w w);
+static void ro_gui_cert_release_window(struct ro_sslcert *s);
/**
- * Load the cert window template
+ * Load and initialise the certificate window template
*/
-void ro_gui_cert_init(void)
+void ro_gui_cert_preinitialise(void)
{
- dialog_tree_template = ro_gui_dialog_load_template("tree");
- dialog_cert_template = ro_gui_dialog_load_template("sslcert");
- dialog_display_template = ro_gui_dialog_load_template("ssldisplay");
+ /* Load templates for the SSL windows and adjust the tree window
+ * flags to suit.
+ */
- dialog_tree_template->flags &= ~(wimp_WINDOW_MOVEABLE |
+ ro_gui_cert_dialog_template = ro_gui_dialog_load_template("sslcert");
+ ro_gui_cert_tree_template = ro_gui_dialog_load_template("tree");
+
+ ro_gui_cert_tree_template->flags &= ~(wimp_WINDOW_MOVEABLE |
wimp_WINDOW_BACK_ICON |
wimp_WINDOW_CLOSE_ICON |
wimp_WINDOW_TITLE_ICON |
@@ -99,169 +88,169 @@
}
/**
+ * Load and initialise the certificate window template
+ */
+
+void ro_gui_cert_postinitialise(void)
+{
+ /* Initialise the SSL module. */
+
+ sslcert_init();
+}
+
+/**
* Open the certificate verification dialog
+ *
+ * \param *bw The browser window owning the certificates.
+ * \param *c The content data corresponding to the
+ * certificates.
+ * \param *certs The certificate details.
+ * \param num The number of certificates included.
*/
void gui_cert_verify(const char *url,
const struct ssl_cert_info *certs, unsigned long num,
nserror (*cb)(bool proceed, void *pw), void *cbpw)
{
- wimp_w w;
- wimp_w ssl_w;
- const struct ssl_cert_info *from;
- struct session_cert *to;
- struct session_data *data;
- struct tree *tree;
- struct node *node;
- wimp_window_state state;
- wimp_icon_state istate;
- os_error *error;
- long i;
+ struct ro_sslcert *sslcert_window;
+ wimp_window_state state;
+ wimp_icon_state istate;
+ wimp_window_info info;
+ os_error *error;
+ bool set_extent;
assert(certs);
- /* copy the certificate information */
- data = calloc(1, sizeof(struct session_data));
- if (!data) {
- warn_user("NoMemory", 0);
+ sslcert_window = malloc(sizeof(struct ro_sslcert));
+ if (sslcert_window == NULL) {
+ LOG(("Failed to allocate memory for SSL Cert Dialog"));
return;
}
- data->url = strdup(url);
- if (!data->url) {
- free(data);
- warn_user("NoMemory", 0);
- return;
- }
- data->cb = cb;
- data->cbpw = cbpw;
- data->num = num;
- data->certs = calloc(num, sizeof(struct session_cert));
- if (!data->certs) {
- free(data->url);
- free(data);
- warn_user("NoMemory", 0);
- return;
- }
- for (i = 0; i < (long)num; i++) {
- to = &data->certs[i];
- from = &certs[i];
- to->subject_t = strdup(from->subject);
- to->issuer_t = strdup(from->issuer);
- if ((!to->subject_t) || (!to->issuer_t)) {
- for (; i >= 0; i--) {
- to = &data->certs[i];
- free(to->subject_t);
- free(to->issuer_t);
- }
- free(data->certs);
- free(data->url);
- free(data);
- warn_user("NoMemory", 0);
- return;
- }
- snprintf(to->version, sizeof data->certs->version, "%ld",
- from->version);
- snprintf(to->valid_from, sizeof data->certs->valid_from, "%s",
- from->not_before);
- snprintf(to->type, sizeof data->certs->type, "%d",
- from->cert_type);
- snprintf(to->valid_to, sizeof data->certs->valid_to, "%s",
- from->not_after);
- snprintf(to->serial, sizeof data->certs->serial, "%ld",
- from->serial);
- }
- /* create the SSL window */
- error = xwimp_create_window(dialog_cert_template, &ssl_w);
+ /* Create the SSL window and its pane. */
+
+ error = xwimp_create_window(ro_gui_cert_dialog_template,
+ &(sslcert_window->window));
if (error) {
- free(data->certs);
- free(data->url);
- free(data);
LOG(("xwimp_create_window: 0x%x: %s",
error->errnum, error->errmess));
+ free(sslcert_window);
return;
}
- /* automated SSL window event handling */
- ro_gui_wimp_event_set_user_data(ssl_w, data);
- ro_gui_wimp_event_register_cancel(ssl_w, ICON_SSL_REJECT);
- ro_gui_wimp_event_register_ok(ssl_w, ICON_SSL_ACCEPT, ro_gui_cert_apply);
- ro_gui_dialog_open_persistent(NULL, ssl_w, false);
-
- /* create a tree window (styled as a list) */
- error = xwimp_create_window(dialog_tree_template, &w);
+ error = xwimp_create_window(ro_gui_cert_tree_template,
+ &(sslcert_window->pane));
if (error) {
- ro_gui_cert_close(ssl_w);
LOG(("xwimp_create_window: 0x%x: %s",
error->errnum, error->errmess));
+ free(sslcert_window);
return;
}
- tree = calloc(sizeof(struct tree), 1);
- if (!tree) {
- ro_gui_cert_close(ssl_w);
- warn_user("NoMemory", 0);
+
+ /* Create the SSL data and build a tree from it. */
+
+ sslcert_window->tv = ro_treeview_create(sslcert_window->pane, NULL,
+ sslcert_get_tree_flags());
+ if (sslcert_window->tv == NULL) {
+ LOG(("Failed to allocate treeview"));
+ free(sslcert_window);
return;
}
- tree->root = tree_create_folder_node(NULL, "Root");
- if (!tree->root) {
- ro_gui_cert_close(ssl_w);
- warn_user("NoMemory", 0);
- free(tree);
- tree = NULL;
- return;
- }
- tree->root->expanded = true;
- tree->handle = (int)w;
- tree->movable = false;
- tree->no_drag = true;
- tree->no_vscroll = true;
- tree->no_furniture = true;
- tree->single_selection = true;
- data->tree = tree;
- /* put the SSL names in the tree */
- for (i = 0; i < (long)num; i++) {
- node = tree_create_leaf_node(tree->root, certs[i].subject);
- if (node) {
- node->data.data = TREE_ELEMENT_SSL;
- tree_set_node_sprite(node, "small_xxx", "small_xxx");
- }
- }
+ sslcert_window->data = sslcert_create_session_data(num, url, cb, cbpw);
+ sslcert_load_tree(ro_treeview_get_tree(sslcert_window->tv),
+ certs, sslcert_window->data);
- /* automated treeview event handling */
- ro_gui_wimp_event_set_user_data(w, tree);
- ro_gui_wimp_event_register_keypress(w, ro_gui_tree_keypress);
- ro_gui_wimp_event_register_redraw_window(w, ro_gui_tree_redraw);
- ro_gui_wimp_event_register_open_window(w, ro_gui_tree_open);
- ro_gui_wimp_event_register_close_window(w, ro_gui_wimp_event_finalise);
- ro_gui_wimp_event_register_mouse_click(w, ro_gui_cert_click);
+ tree_set_redraw(ro_treeview_get_tree(sslcert_window->tv), true);
- /* nest the tree window inside the pane window */
- state.w = ssl_w;
+ /* Set up the certificate window event handling.
+ *
+ * (The action buttons are registered as button events, not OK and
+ * Cancel, as both need to carry out actions.)
+ */
+
+ ro_gui_wimp_event_set_user_data(sslcert_window->window, sslcert_window);
+ ro_gui_wimp_event_register_close_window(sslcert_window->window,
+ ro_gui_cert_close_window);
+ ro_gui_wimp_event_register_button(sslcert_window->window,
+ ICON_SSL_REJECT, ro_gui_cert_reject);
+ ro_gui_wimp_event_register_button(sslcert_window->window,
+ ICON_SSL_ACCEPT, ro_gui_cert_accept);
+
+ ro_gui_dialog_open_persistent(NULL, sslcert_window->window, false);
+
+ /* Nest the tree window inside the pane window. To do this, we:
+ * - Get the current pane extent,
+ * - Get the parent window position and the location of the pane-
+ * locating icon inside it,
+ * - Set the visible area of the pane to suit,
+ * - Check that the pane extents are OK for this visible area, and
+ * increase them if necessary,
+ * - Before finally opening the pane as a nested part of the parent.
+ */
+
+ info.w = sslcert_window->pane;
+ error = xwimp_get_window_info_header_only(&info);
+ if (error) {
+ ro_gui_cert_release_window(sslcert_window);
+ LOG(("xwimp_get_window_info: 0x%x: %s",
+ error->errnum, error->errmess));
+ return;
+ }
+
+ state.w = sslcert_window->window;
error = xwimp_get_window_state(&state);
if (error) {
- ro_gui_cert_close(ssl_w);
+ ro_gui_cert_release_window(sslcert_window);
LOG(("xwimp_get_window_state: 0x%x: %s",
error->errnum, error->errmess));
return;
}
- istate.w = ssl_w;
+ istate.w = sslcert_window->window;
istate.i = ICON_SSL_PANE;
error = xwimp_get_icon_state(&istate);
if (error) {
- ro_gui_cert_close(ssl_w);
+ ro_gui_cert_release_window(sslcert_window);
LOG(("xwimp_get_icon_state: 0x%x: %s",
error->errnum, error->errmess));
return;
}
- state.w = w;
+
+ state.w = sslcert_window->pane;
state.visible.x1 = state.visible.x0 + istate.icon.extent.x1 - 20 -
- ro_get_vscroll_width(w);
+ ro_get_vscroll_width(sslcert_window->pane);
state.visible.x0 += istate.icon.extent.x0 + 20;
state.visible.y0 = state.visible.y1 + istate.icon.extent.y0 + 20;
state.visible.y1 += istate.icon.extent.y1 - 32;
- error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state), ssl_w,
+
+ set_extent = false;
+
+ if ((info.extent.x1 - info.extent.x0) <
+ (state.visible.x1 - state.visible.x0)) {
+ info.extent.x0 = 0;
+ info.extent.x1 = state.visible.x1 - state.visible.x0;
+ set_extent = true;
+ }
+ if ((info.extent.y1 - info.extent.y0) <
+ (state.visible.y1 - state.visible.y0)) {
+ info.extent.y1 = 0;
+ info.extent.x1 = state.visible.y0 - state.visible.y1;
+ set_extent = true;
+ }
+
+ if (set_extent) {
+ error = xwimp_set_extent(sslcert_window->pane, &(info.extent));
+ if (error) {
+ ro_gui_cert_release_window(sslcert_window);
+ LOG(("xwimp_set_extent: 0x%x: %s",
+ error->errnum, error->errmess));
+ return;
+ }
+ }
+
+ error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state),
+ sslcert_window->window,
wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
<< wimp_CHILD_XORIGIN_SHIFT |
wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
@@ -271,192 +260,100 @@
wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
<< wimp_CHILD_RS_EDGE_SHIFT);
if (error) {
- ro_gui_cert_close(ssl_w);
+ ro_gui_cert_release_window(sslcert_window);
LOG(("xwimp_open_window_nested: 0x%x: %s",
error->errnum, error->errmess));
+ ro_gui_cert_release_window(sslcert_window);
return;
}
- tree_initialise(tree);
}
-void ro_gui_cert_open(struct tree *tree, struct node *node)
+/**
+ * Handle acceptance of certificate via event callback.
+ *
+ * \param *pointer The wimp pointer block.
+ */
+
+void ro_gui_cert_accept(wimp_pointer *pointer)
{
- struct node *n;
- struct session_data *data;
- struct session_cert *session;
- wimp_window_state state;
- wimp_w child;
- wimp_w parent;
- wimp_w w;
- unsigned long i;
- os_error *error;
+ struct ro_sslcert *s;
- assert(tree->root);
+ s = (struct ro_sslcert *) ro_gui_wimp_event_get_user_data(pointer->w);
- /* firstly we need to get our node index in the list */
- for (n = tree->root->child, i = 0; n; i++, n = n->next)
- if (n == node)
- break;
- assert(n);
-
- /* now we get the handle of our list window */
- child = (wimp_w)tree->handle;
- assert(child);
-
- /* now we can get the linked parent handle */
- state.w = child;
- error = xwimp_get_window_state_and_nesting(&state, &parent, 0);
- if (error) {
- LOG(("xwimp_get_window_state: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("WimpError", error->errmess);
- return;
+ if (s != NULL) {
+ sslcert_accept(s->data);
+ ro_gui_dialog_close(s->window);
+ ro_gui_cert_release_window(s);
}
- assert(parent);
+}
- /* from this we can get our session data */
- data = (struct session_data *)ro_gui_wimp_event_get_user_data(parent);
- assert(data);
- assert(data->tree == tree);
+/**
+ * Handle rejection of certificate via event callback.
+ *
+ * \param w The wimp pointer block.
+ */
- /* and finally the nodes session certificate data */
- session = &data->certs[i];
- assert(session);
+void ro_gui_cert_reject(wimp_pointer *pointer)
+{
+ struct ro_sslcert *s;
- dialog_display_template->icons[ICON_CERT_VERSION].data.indirected_text.text = session->version;
- dialog_display_template->icons[ICON_CERT_VERSION].data.indirected_text.size = strlen(session->version) + 1;
- dialog_display_template->icons[ICON_CERT_VALID_FROM].data.indirected_text.text = session->valid_from;
- dialog_display_template->icons[ICON_CERT_VALID_FROM].data.indirected_text.size = strlen(session->valid_from) + 1;
- dialog_display_template->icons[ICON_CERT_TYPE].data.indirected_text.text = session->type;
- dialog_display_template->icons[ICON_CERT_TYPE].data.indirected_text.size = strlen(session->type) + 1;
- dialog_display_template->icons[ICON_CERT_VALID_TO].data.indirected_text.text = session->valid_to;
- dialog_display_template->icons[ICON_CERT_VALID_TO].data.indirected_text.size = strlen(session->valid_to) + 1;
- dialog_display_template->icons[ICON_CERT_SERIAL].data.indirected_text.text = session->serial;
- dialog_display_template->icons[ICON_CERT_SERIAL].data.indirected_text.size = strlen(session->serial) + 1;
+ s = (struct ro_sslcert *) ro_gui_wimp_event_get_user_data(pointer->w);
- error = xwimp_create_window(dialog_display_template, &w);
- if (error) {
- LOG(("xwimp_create_window: 0x%x: %s",
- error->errnum, error->errmess));
- free(session);
- warn_user("MiscError", error->errmess);
- return;
+ if (s != NULL) {
+ sslcert_reject(s->data);
+ ro_gui_dialog_close(s->window);
+ ro_gui_cert_release_window(s);
}
- if (session->issuer)
- ro_textarea_destroy(session->issuer);
- session->issuer = ro_textarea_create(w, ICON_CERT_ISSUER,
- TEXTAREA_MULTILINE | TEXTAREA_READONLY,
- ro_gui_desktop_font_family, ro_gui_desktop_font_size,
- ro_gui_desktop_font_style);
- if (!session->issuer) {
- xwimp_delete_window(w);
- warn_user("NoMemory", 0);
- return;
- }
- if (!ro_textarea_set_text(session->issuer, session->issuer_t)) {
- ro_textarea_destroy(session->issuer);
- xwimp_delete_window(w);
- warn_user("NoMemory", 0);
- return;
- }
-
- if (session->subject)
- ro_textarea_destroy(session->subject);
- session->subject = ro_textarea_create(w, ICON_CERT_SUBJECT,
- TEXTAREA_MULTILINE | TEXTAREA_READONLY,
- ro_gui_desktop_font_family, ro_gui_desktop_font_size,
- ro_gui_desktop_font_style);
- if (!session->subject) {
- ro_textarea_destroy(session->issuer);
- xwimp_delete_window(w);
- warn_user("NoMemory", 0);
- return;
- }
- if (!ro_textarea_set_text(session->subject, session->subject_t)) {
- ro_textarea_destroy(session->subject);
- ro_textarea_destroy(session->issuer);
- xwimp_delete_window(w);
- warn_user("NoMemory", 0);
- return;
- }
- ro_gui_wimp_event_register_close_window(w, ro_gui_wimp_event_finalise);
- ro_gui_dialog_open_persistent(parent, w, false);
}
/**
- * Handle closing of certificate verification dialog
+ * Callback to handle the closure of the SSL dialogue by other means.
+ *
+ * \param w The window being closed.
*/
-void ro_gui_cert_close(wimp_w w)
+
+static void ro_gui_cert_close_window(wimp_w w)
{
- struct session_data *data;
- os_error *error;
- unsigned long i;
+ struct ro_sslcert *s;
- data = (struct session_data *)ro_gui_wimp_event_get_user_data(w);
- assert(data);
+ s = (struct ro_sslcert *) ro_gui_wimp_event_get_user_data(w);
- /* If we didn't accept the certificate, send failure response */
- if (data->cb != NULL)
- data->cb(false, data->cbpw);
-
- for (i = 0; i < data->num; i++) {
- if (data->certs[i].subject)
- ro_textarea_destroy(data->certs[i].subject);
- if (data->certs[i].issuer)
- ro_textarea_destroy(data->certs[i].issuer);
- }
- free(data->certs);
- free(data->url);
- if (data->tree) {
- tree_delete_node(data->tree, data->tree->root, false);
- ro_gui_dialog_close((wimp_w)data->tree->handle);
- error = xwimp_delete_window((wimp_w)data->tree->handle);
- if (error) {
- LOG(("xwimp_delete_window: 0x%x:%s",
- error->errnum, error->errmess));
- warn_user("WimpError", error->errmess);
- }
- ro_gui_wimp_event_finalise((wimp_w)data->tree->handle);
- free(data->tree);
- }
- free(data);
-
- ro_gui_dialog_close(w);
- error = xwimp_delete_window(w);
- if (error) {
- LOG(("xwimp_delete_window: 0x%x:%s",
- error->errnum, error->errmess));
- warn_user("WimpError", error->errmess);
- }
-
+ if (s != NULL)
+ ro_gui_cert_release_window(s);
}
/**
- * Handle acceptance of certificate
+ * Handle closing of the RISC OS certificate verification dialog, deleting
+ * the windows and freeing up the treeview and data block.
+ *
+ * \param *s The data block associated with the dialogue.
*/
-bool ro_gui_cert_apply(wimp_w w)
+
+void ro_gui_cert_release_window(struct ro_sslcert *s)
{
- struct session_data *session;
+ os_error *error;
- session = (struct session_data *)ro_gui_wimp_event_get_user_data(w);
- assert(session);
+ if (s == NULL)
+ return;
- urldb_set_cert_permissions(session->url, true);
- session->cb(true, session->cbpw);
+ LOG(("Releasing SSL data: 0x%x", (unsigned) s));
- /* Flag that we sent response by invalidating callback details */
- session->cb = NULL;
- session->cbpw = NULL;
+ ro_gui_wimp_event_finalise(s->window);
+ ro_treeview_destroy(s->tv);
- return true;
-}
+ error = xwimp_delete_window(s->window);
+ if (error) {
+ LOG(("xwimp_delete_window: 0x%x:%s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
+ error = xwimp_delete_window(s->pane);
+ if (error) {
+ LOG(("xwimp_delete_window: 0x%x:%s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
-bool ro_gui_cert_click(wimp_pointer *pointer)
-{
- struct tree *tree;
-
- tree = (struct tree *)ro_gui_wimp_event_get_user_data(pointer->w);
- ro_gui_tree_click(pointer, tree);
- return true;
+ free(s);
}
Index: riscos/global_history.c
===================================================================
--- riscos/global_history.c (revision 10834)
+++ riscos/global_history.c (working copy)
@@ -1,5 +1,6 @@
/*
* Copyright 2005 Richard Wilson <info(a)tinct.net>
+ * Copyright 2010 Stephen Fryatt <stevef(a)netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -29,12 +30,14 @@
#include "oslib/wimp.h"
#include "oslib/wimpspriteop.h"
#include "content/urldb.h"
+#include "desktop/history_global_core.h"
#include "desktop/tree.h"
#include "riscos/dialog.h"
#include "riscos/global_history.h"
#include "riscos/gui.h"
#include "riscos/menus.h"
#include "riscos/options.h"
+#include "riscos/save.h"
#include "riscos/theme.h"
#include "riscos/treeview.h"
#include "riscos/wimp.h"
@@ -44,401 +47,260 @@
#include "utils/url.h"
#include "utils/utils.h"
-#define MAXIMUM_URL_LENGTH 1024
-#define MAXIMUM_BASE_NODES 16
+static void ro_gui_global_history_menu_prepare(wimp_w window, wimp_menu *menu);
+static bool ro_gui_global_history_menu_select(wimp_w window, wimp_menu *menu,
+ wimp_selection *selection, menu_action action);
+static void ro_gui_global_history_menu_warning(wimp_w window, wimp_menu *menu,
+ wimp_selection *selection, menu_action action);
-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;
+/* The RISC OS global history window, toolbar and treeview data */
-static char *global_history_recent_url[GLOBAL_HISTORY_RECENT_URLS];
-static int global_history_recent_count = 0;
+static struct ro_global_history_window {
+ wimp_w window;
+ struct toolbar *toolbar;
+ ro_treeview *tv;
+ wimp_menu *menu;
+} global_history_window;
-static bool global_history_init;
-
-static bool ro_gui_global_history_click(wimp_pointer *pointer);
-static void ro_gui_global_history_initialise_nodes(void);
-static void ro_gui_global_history_initialise_node(const char *title,
- time_t base, int days_back);
-static struct node *ro_gui_global_history_find(const char *url);
-static bool global_history_add_internal(const char *url,
- const struct url_data *data);
-
-/* The history window, toolbar and plot origins */
-static wimp_w global_history_window;
-struct tree *global_history_tree;
-
/**
- * Initialise global history tree
+ * Pre-Initialise the global history tree. This is called for things that
+ * need to be done at the gui_init() stage, such as loading templates.
*/
-void ro_gui_global_history_initialise(void)
+
+void ro_gui_global_history_preinitialise(void)
{
- char s[MAXIMUM_URL_LENGTH];
- FILE *fp;
+ /* Create our window. */
- /* create our window */
- global_history_window = ro_gui_dialog_create("tree");
- ro_gui_set_window_title(global_history_window,
+ global_history_window.window = ro_gui_dialog_create("tree");
+ ro_gui_set_window_title(global_history_window.window,
messages_get("GlobalHistory"));
- ro_gui_wimp_event_register_redraw_window(global_history_window,
- ro_gui_tree_redraw);
- ro_gui_wimp_event_register_open_window(global_history_window,
- ro_gui_tree_open);
- ro_gui_wimp_event_register_mouse_click(global_history_window,
- ro_gui_global_history_click);
-
- /* Create an empty tree */
- global_history_tree = calloc(sizeof(struct tree), 1);
- if (!global_history_tree) {
- warn_user("NoMemory", 0);
- return;
- }
- global_history_tree->root = tree_create_folder_node(NULL, "Root");
- if (!global_history_tree->root) {
- warn_user("NoMemory", 0);
- free(global_history_tree);
- global_history_tree = NULL;
- return;
- }
- global_history_tree->root->expanded = true;
- ro_gui_global_history_initialise_nodes();
- global_history_tree->handle = (int)global_history_window;
- global_history_tree->movable = false;
- ro_gui_wimp_event_set_user_data(global_history_window,
- global_history_tree);
- ro_gui_wimp_event_register_keypress(global_history_window,
- ro_gui_tree_keypress);
-
- /* Create our toolbar */
- global_history_tree->toolbar = ro_gui_theme_create_toolbar(NULL,
- THEME_HISTORY_TOOLBAR);
- if (global_history_tree->toolbar)
- ro_gui_theme_attach_toolbar(global_history_tree->toolbar,
- global_history_window);
-
- /* load recent URLs */
- fp = fopen(option_recent_path, "r");
- if (!fp)
- LOG(("Failed to open file '%s' for reading",
- option_recent_path));
- else {
- while (fgets(s, MAXIMUM_URL_LENGTH, fp)) {
- if (s[strlen(s) - 1] == '\n')
- s[strlen(s) - 1] = '\0';
- global_history_add_recent(s);
- }
- fclose(fp);
- }
-
- global_history_init = true;
- urldb_iterate_entries(global_history_add_internal);
- global_history_init = false;
- tree_initialise(global_history_tree);
}
/**
- * Initialises the base nodes
+ * Initialise global history tree, at the gui_init2() stage.
*/
-void ro_gui_global_history_initialise_nodes(void)
+
+void ro_gui_global_history_postinitialise(void)
{
- struct tm *full_time;
- time_t t;
- int weekday;
- int i;
- /* get the current time */
- t = time(NULL);
- if (t == -1)
- return;
+ /* Create our toolbar. */
- /* 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)
+ global_history_window.toolbar = ro_gui_theme_create_toolbar(NULL,
+ THEME_HISTORY_TOOLBAR);
+ if (global_history_window.toolbar)
+ ro_gui_theme_attach_toolbar(global_history_window.toolbar,
+ global_history_window.window);
+
+ /* Create the treeview with the window and toolbar. */
+
+ global_history_window.tv =
+ ro_treeview_create(global_history_window.window,
+ global_history_window.toolbar,
+ history_global_get_tree_flags());
+ if (global_history_window.tv == NULL) {
+ LOG(("Failed to allocate treeview"));
return;
+ }
- ro_gui_global_history_initialise_node(messages_get("DateToday"), t, 0);
- if (weekday > 0)
- ro_gui_global_history_initialise_node(
- messages_get("DateYesterday"), t, -1);
- for (i = 2; i <= weekday; i++)
- ro_gui_global_history_initialise_node(NULL, t, -i);
- ro_gui_global_history_initialise_node(messages_get("Date1Week"),
- t, -weekday - 7);
- ro_gui_global_history_initialise_node(messages_get("Date2Week"),
- t, -weekday - 14);
- ro_gui_global_history_initialise_node(messages_get("Date3Week"),
- t, -weekday - 21);
-}
+ /* Initialise the global history into the tree. */
-/**
- * Create and initialise a node
- */
-void ro_gui_global_history_initialise_node(const char *title,
- time_t base, int days_back)
-{
- struct tm *full_time;
- char buffer[64];
- struct node *node;
+ history_global_initialise(
+ ro_treeview_get_tree(global_history_window.tv));
- base += days_back * 60 * 60 * 24;
- if (!title) {
- full_time = localtime(&base);
- strftime((char *)&buffer, (size_t)64, "%A", full_time);
- node = tree_create_folder_node(NULL, buffer);
- } else
- node = tree_create_folder_node(NULL, title);
+ /* Build the global history window menu. */
- if (!node)
- return;
+ static const struct ns_menu global_history_definition = {
+ "History", {
+ { "History", NO_ACTION, 0 },
+ { "_History.Export", HISTORY_EXPORT, &dialog_saveas },
+ { "History.Expand", TREE_EXPAND_ALL, 0 },
+ { "History.Expand.All", TREE_EXPAND_ALL, 0 },
+ { "History.Expand.Folders", TREE_EXPAND_FOLDERS, 0 },
+ { "History.Expand.Links", TREE_EXPAND_LINKS, 0 },
+ { "History.Collapse", TREE_COLLAPSE_ALL, 0 },
+ { "History.Collapse.All", TREE_COLLAPSE_ALL, 0 },
+ { "History.Collapse.Folders", TREE_COLLAPSE_FOLDERS, 0 },
+ { "History.Collapse.Links", TREE_COLLAPSE_LINKS, 0 },
+ { "History.Toolbars", NO_ACTION, 0 },
+ { "_History.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 },
+ { "History.Toolbars.EditToolbar",TOOLBAR_EDIT, 0 },
+ { "Selection", TREE_SELECTION, 0 },
+ { "Selection.Launch", TREE_SELECTION_LAUNCH, 0 },
+ { "Selection.Delete", TREE_SELECTION_DELETE, 0 },
+ { "SelectAll", TREE_SELECT_ALL, 0 },
+ { "Clear", TREE_CLEAR_SELECTION, 0 },
+ {NULL, 0, 0}
+ }
+ };
+ global_history_window.menu = ro_gui_menu_define_menu(
+ &global_history_definition);
- node->retain_in_memory = true;
- node->deleted = true;
- node->editable = false;
- 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++;
+ ro_gui_wimp_event_register_window_menu(global_history_window.window,
+ global_history_window.menu,
+ ro_gui_global_history_menu_prepare,
+ ro_gui_global_history_menu_select, NULL,
+ ro_gui_global_history_menu_warning, false);
}
-
/**
- * Saves the global history's recent URL data.
+ * Open the global history window.
*/
-void ro_gui_global_history_save(void)
+
+void ro_gui_global_history_open(void)
{
- FILE *fp;
- int i;
+ tree_set_redraw(ro_treeview_get_tree(global_history_window.tv), true);
- /* save recent URLs */
- fp = fopen(option_recent_save, "w");
- if (!fp)
- LOG(("Failed to open file '%s' for writing",
- option_recent_save));
- else {
- for (i = global_history_recent_count - 1; i >= 0; i--)
- if (strlen(global_history_recent_url[i]) <
- MAXIMUM_URL_LENGTH)
- fprintf(fp, "%s\n",
- global_history_recent_url[i]);
- fclose(fp);
+ if (!ro_gui_dialog_open_top(global_history_window.window,
+ global_history_window.toolbar, 600, 800)) {
+ ro_treeview_set_origin(global_history_window.tv, 0,
+ -(ro_gui_theme_toolbar_height(
+ global_history_window.toolbar)));
}
}
-
/**
- * Respond to a mouse click
+ * Prepare the global history menu for opening
*
- * \param pointer the pointer state
- * \return true to indicate click handled
+ * \param window The window owning the menu.
+ * \param *menu The menu about to be opened.
*/
-bool ro_gui_global_history_click(wimp_pointer *pointer)
+
+void ro_gui_global_history_menu_prepare(wimp_w window, wimp_menu *menu)
{
- ro_gui_tree_click(pointer, global_history_tree);
- if (pointer->buttons == wimp_CLICK_MENU)
- ro_gui_menu_create(global_history_menu, pointer->pos.x,
- pointer->pos.y, pointer->w);
- else
- ro_gui_menu_prepare_action(pointer->w, TREE_SELECTION, false);
- return true;
-}
+ bool selection;
+ selection = ro_treeview_has_selection(global_history_window.tv);
+ ro_gui_menu_set_entry_shaded(global_history_window.menu,
+ TREE_SELECTION, !selection);
+ ro_gui_menu_set_entry_shaded(global_history_window.menu,
+ TREE_CLEAR_SELECTION, !selection);
+
+ ro_gui_menu_set_entry_shaded(global_history_window.menu,
+ TOOLBAR_BUTTONS,
+ (global_history_window.toolbar == NULL ||
+ global_history_window.toolbar->editor));
+ ro_gui_menu_set_entry_ticked(global_history_window.menu,
+ TOOLBAR_BUTTONS,
+ (global_history_window.toolbar != NULL &&
+ (global_history_window.toolbar->display_buttons ||
+ (global_history_window.toolbar->editor))));
+
+ ro_gui_menu_set_entry_shaded(global_history_window.menu, TOOLBAR_EDIT,
+ global_history_window.toolbar == NULL);
+ ro_gui_menu_set_entry_ticked(global_history_window.menu, TOOLBAR_EDIT,
+ (global_history_window.toolbar != NULL &&
+ global_history_window.toolbar->editor));
+
+ ro_gui_save_prepare(GUI_SAVE_HISTORY_EXPORT_HTML,
+ NULL, NULL, NULL, NULL);
+}
+
/**
- * Adds to the global history
+ * Handle submenu warnings for the global_hostory menu
*
- * \param url The URL to add
+ * \param window The window owning the menu.
+ * \param *menu The menu to which the warning applies.
+ * \param *selection The wimp menu selection data.
+ * \param action The selected menu action.
*/
-void global_history_add(const char *url)
-{
- const struct url_data *data;
- data = urldb_get_url_data(url);
- if (!data)
- return;
-
- global_history_add_internal(url, data);
+void ro_gui_global_history_menu_warning(wimp_w window, wimp_menu *menu,
+ wimp_selection *selection, menu_action action)
+{
+ /* Do nothing */
}
/**
- * Internal routine to actually perform global history addition
+ * Handle selections from the global history menu
*
- * \param url The URL to add
- * \param data URL data associated with URL
- * \return true (for urldb_iterate_entries)
+ * \param window The window owning the menu.
+ * \param *menu The menu from which the selection was made.
+ * \param *selection The wimp menu selection data.
+ * \param action The selected menu action.
+ * \return true if action accepted; else false.
*/
-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 && data);
-
- 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)
+bool ro_gui_global_history_menu_select(wimp_w window, wimp_menu *menu,
+ wimp_selection *selection, menu_action action)
+{
+ switch (action) {
+ case HISTORY_EXPORT:
+ ro_gui_dialog_open_persistent(window, dialog_saveas, true);
return true;
-
- if (parent->deleted) {
- /* 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 (!global_history_base_node[j]->deleted &&
- 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, false);
- tree_set_node_expanded(global_history_tree,
- parent, false);
- tree_link_node(link, parent, before);
-
- if (!global_history_init) {
- tree_recalculate_node(global_history_tree, parent, true);
- tree_recalculate_node_positions(global_history_tree,
- global_history_tree->root);
- tree_redraw_area(global_history_tree,
- 0, 0, 16384, 16384);
- }
+ case TREE_EXPAND_ALL:
+ history_global_expand_all();
+ return true;
+ case TREE_EXPAND_FOLDERS:
+ history_global_expand_directories();
+ return true;
+ case TREE_EXPAND_LINKS:
+ history_global_expand_addresses();
+ return true;
+ case TREE_COLLAPSE_ALL:
+ history_global_collapse_all();
+ return true;
+ case TREE_COLLAPSE_FOLDERS:
+ history_global_collapse_directories();
+ return true;
+ case TREE_COLLAPSE_LINKS:
+ history_global_collapse_addresses();
+ return true;
+ case TREE_SELECTION_LAUNCH:
+ history_global_launch_selected();
+ return true;
+ case TREE_SELECTION_DELETE:
+ history_global_delete_selected();
+ return true;
+ case TREE_SELECT_ALL:
+ history_global_select_all();
+ return true;
+ case TREE_CLEAR_SELECTION:
+ history_global_clear_selection();
+ return true;
+ default:
+ return false;
}
- /* find any previous occurance */
- if (!global_history_init) {
- node = ro_gui_global_history_find(url);
- if (node) {
- /* \todo: calculate old/new positions and redraw
- * only the relevant portion */
- tree_redraw_area(global_history_tree,
- 0, 0, 16384, 16384);
- tree_update_URL_node(node, url, data);
- tree_delink_node(node);
- tree_link_node(parent, node, false);
- tree_handle_node_changed(global_history_tree,
- node, false, true);
-/* ro_gui_tree_scroll_visible(hotlist_tree,
- &node->data);
-*/ return true;
- }
- }
-
- /* Add the node at the bottom */
- node = tree_create_URL_node_shared(parent, url, data);
- if ((!global_history_init) && (node)) {
- tree_redraw_area(global_history_tree,
- node->box.x - NODE_INSTEP,
- 0, NODE_INSTEP, 16384);
- tree_handle_node_changed(global_history_tree, node,
- true, false);
- }
-
- return true;
+ return false;
}
/**
- * Find an entry in the global history
- *
- * \param url The URL to find
- * \return Pointer to node, or NULL if not found
+ * Update the theme details of the global history window.
*/
-struct node *ro_gui_global_history_find(const char *url)
-{
- int i;
- struct node *node;
- struct node_element *element;
- for (i = 0; i < global_history_base_node_count; i++) {
- if (!global_history_base_node[i]->deleted) {
- for (node = global_history_base_node[i]->child;
- node; node = node->next) {
- element = tree_find_element(node,
- TREE_ELEMENT_URL);
- if ((element) && !strcmp(url, element->text))
- return node;
- }
- }
- }
- return NULL;
+void ro_gui_global_history_update_theme(void)
+{
+ ro_treeview_update_theme(global_history_window.tv);
}
-
/**
- * Adds an URL to the recently used list
+ * Check if a particular window handle is the global history window
*
- * \param url the URL to add (copied)
+ * \param window the window in question
+ * \return true if this window is the global history
*/
-void global_history_add_recent(const char *url)
-{
- int i;
- int j = -1;
- char *current;
- /* try to find a string already there */
- for (i = 0; i < global_history_recent_count; i++)
- if (global_history_recent_url[i] &&
- !strcmp(global_history_recent_url[i], url))
- j = i;
-
- /* already at head of list */
- if (j == 0)
- return;
-
- if (j < 0) {
- /* add to head of list */
- free(global_history_recent_url[
- GLOBAL_HISTORY_RECENT_URLS - 1]);
- memmove(&global_history_recent_url[1],
- &global_history_recent_url[0],
- (GLOBAL_HISTORY_RECENT_URLS - 1) *
- sizeof(char *));
- global_history_recent_url[0] = strdup(url);
- global_history_recent_count++;
- if (global_history_recent_count > GLOBAL_HISTORY_RECENT_URLS)
- global_history_recent_count =
- GLOBAL_HISTORY_RECENT_URLS;
- if (global_history_recent_count == 1)
- ro_gui_window_prepare_navigate_all();
- } else {
- /* move to head of list */
- current = global_history_recent_url[j];
- for (i = j; i > 0; i--)
- global_history_recent_url[i] =
- global_history_recent_url[i - 1];
- global_history_recent_url[0] = current;
- }
+bool ro_gui_global_history_check_window(wimp_w window)
+{
+/* if (global_history_window.w == window)
+ return true;
+ else*/
+ return false;
}
-
/**
- * Gets details of the currently used URL list.
+ * Check if a particular menu handle is the global history menu
*
- * \param count set to the current number of entries in the URL array on exit
- * \return the current URL array
+ * \param *menu The menu in question.
+ * \return true if this menu is the global history menu
*/
-char **global_history_get_recent(int *count)
+
+bool ro_gui_global_history_check_menu(wimp_menu *menu)
{
- *count = global_history_recent_count;
- return global_history_recent_url;
+ if (global_history_window.menu == menu)
+ return true;
+ else
+ return false;
}
+
Index: riscos/global_history.h
===================================================================
--- riscos/global_history.h (revision 10834)
+++ riscos/global_history.h (working copy)
@@ -1,5 +1,6 @@
/*
* Copyright 2005 Richard Wilson <info(a)tinct.net>
+ * Copyright 2010 Stephen Fryatt <stevef(a)netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -23,10 +24,13 @@
#ifndef _NETSURF_RISCOS_GLOBALHISTORY_H_
#define _NETSURF_RISCOS_GLOBALHISTORY_H_
-#define GLOBAL_HISTORY_RECENT_URLS 16
-
-void ro_gui_global_history_initialise(void);
+void ro_gui_global_history_preinitialise(void);
+void ro_gui_global_history_postinitialise(void);
+void ro_gui_global_history_open(void);
void ro_gui_global_history_save(void);
+void ro_gui_global_history_update_theme(void);
+bool ro_gui_global_history_check_window(wimp_w window);
+bool ro_gui_global_history_check_menu(wimp_menu *menu);
+#endif
-#endif
Index: riscos/hotlist.c
===================================================================
--- riscos/hotlist.c (revision 10834)
+++ riscos/hotlist.c (working copy)
@@ -1,5 +1,6 @@
/*
* Copyright 2004, 2005 Richard Wilson <info(a)tinct.net>
+ * Copyright 2010 Stephen Fryatt <stevef(a)netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -31,10 +32,13 @@
#include "content/content.h"
#include "content/hlcache.h"
#include "content/urldb.h"
+#include "desktop/hotlist.h"
#include "desktop/tree.h"
#include "riscos/dialog.h"
+#include "riscos/hotlist.h"
#include "riscos/menus.h"
#include "riscos/options.h"
+#include "riscos/save.h"
#include "riscos/theme.h"
#include "riscos/treeview.h"
#include "riscos/wimp.h"
@@ -44,350 +48,300 @@
#include "utils/utils.h"
#include "utils/url.h"
+static void ro_gui_hotlist_menu_prepare(wimp_w window, wimp_menu *menu);
+static bool ro_gui_hotlist_menu_select(wimp_w window, wimp_menu *menu,
+ wimp_selection *selection, menu_action action);
+static void ro_gui_hotlist_menu_warning(wimp_w window, wimp_menu *menu,
+ wimp_selection *selection, menu_action action);
-static void ro_gui_hotlist_visited(hlcache_handle *c, struct tree *tree,
- struct node *node);
-static bool ro_gui_hotlist_click(wimp_pointer *pointer);
+/* The RISC OS hotlist window, toolbar and treeview data. */
+static struct ro_hotlist {
+ wimp_w window; /*< The hotlist RO window handle. */
+ struct toolbar *toolbar; /*< The hotlist toolbar handle. */
+ ro_treeview *tv; /*< The hotlist treeview handle. */
+ wimp_menu *menu; /*< The hotlist window menu. */
+} hotlist_window;
-/* The hotlist window, toolbar and plot origins
-*/
-static wimp_w hotlist_window;
-struct tree *hotlist_tree;
+/**
+ * Pre-Initialise the hotlist tree. This is called for things that need to
+ * be done at the gui_init() stage, such as loading templates.
+ */
-/* Whether the editing facilities are for add so that we know how
- to reset the dialog boxes on a adjust-cancel and the action to
- perform on ok.
-*/
-struct node *dialog_folder_node;
-struct node *dialog_entry_node;
+void ro_gui_hotlist_preinitialise(void)
+{
+ /* Create our window. */
-static const struct {
- const char *url;
- const char *msg_key;
-} default_entries[] = {
- { "http://www.netsurf-browser.org/", "HotlistHomepage" },
- { "http://www.netsurf-browser.org/downloads/riscos/testbuilds", "HotlistTestBuild" },
- { "http://www.netsurf-browser.org/documentation", "HotlistDocumentation" },
- { "http://sourceforge.net/tracker/?atid=464312&group_id=51719",
- "HotlistBugTracker" },
- { "http://sourceforge.net/tracker/?atid=464315&group_id=51719",
- "HotlistFeatureRequest" }
-};
-#define ENTRIES_COUNT (sizeof(default_entries) / sizeof(default_entries[0]))
+ hotlist_window.window = ro_gui_dialog_create("tree");
+ ro_gui_set_window_title(hotlist_window.window,
+ messages_get("Hotlist"));
+}
-void ro_gui_hotlist_initialise(void)
+/**
+ * Initialise the hotlist tree, at the gui_init2() stage.
+ */
+
+void ro_gui_hotlist_postinitialise(void)
{
- FILE *fp;
- struct node *node;
- const struct url_data *data;
+ /* Create our toolbar. */
- /* create our window */
- hotlist_window = ro_gui_dialog_create("tree");
- ro_gui_set_window_title(hotlist_window,
- messages_get("Hotlist"));
- ro_gui_wimp_event_register_redraw_window(hotlist_window,
- ro_gui_tree_redraw);
- ro_gui_wimp_event_register_open_window(hotlist_window,
- ro_gui_tree_open);
- ro_gui_wimp_event_register_mouse_click(hotlist_window,
- ro_gui_hotlist_click);
+ hotlist_window.toolbar = ro_gui_theme_create_toolbar(NULL,
+ THEME_HOTLIST_TOOLBAR);
+ if (hotlist_window.toolbar)
+ ro_gui_theme_attach_toolbar(hotlist_window.toolbar,
+ hotlist_window.window);
- /* Either load or create a hotlist
- */
- fp = fopen(option_hotlist_path, "r");
- if (!fp) {
- int i;
+ /* Create the treeview with the window and toolbar. */
- hotlist_tree = calloc(sizeof(struct tree), 1);
- if (!hotlist_tree) {
- warn_user("NoMemory", 0);
- return;
- }
- hotlist_tree->root = tree_create_folder_node(NULL, "Root");
- if (!hotlist_tree->root) {
- warn_user("NoMemory", 0);
- free(hotlist_tree);
- hotlist_tree = NULL;
- return;
- }
- hotlist_tree->root->expanded = true;
- node = tree_create_folder_node(hotlist_tree->root, "NetSurf");
- if (!node)
- node = hotlist_tree->root;
+ hotlist_window.tv = ro_treeview_create(hotlist_window.window,
+ hotlist_window.toolbar, hotlist_get_tree_flags());
+ if (hotlist_window.tv == NULL) {
+ LOG(("Failed to allocate treeview"));
+ return;
+ }
- for (i = 0; i != ENTRIES_COUNT; i++) {
- data = urldb_get_url_data(default_entries[i].url);
- if (!data) {
- urldb_add_url(default_entries[i].url);
- urldb_set_url_persistence(
- default_entries[i].url,
- true);
- data = urldb_get_url_data(
- default_entries[i].url);
- }
- if (data) {
- tree_create_URL_node(node,
- default_entries[i].url, data,
- messages_get(default_entries[i].msg_key));
- }
+ /* Initialise the hotlist into the tree. */
+
+ hotlist_initialise(ro_treeview_get_tree(hotlist_window.tv),
+ option_hotlist_path);
+
+
+ /* Build the hotlist window menu. */
+
+ static const struct ns_menu hotlist_definition = {
+ "Hotlist", {
+ { "Hotlist", NO_ACTION, 0 },
+ { "Hotlist.New", NO_ACTION, 0 },
+ { "Hotlist.New.Folder", TREE_NEW_FOLDER, 0 },
+ { "Hotlist.New.Link", TREE_NEW_LINK, 0 },
+ { "_Hotlist.Export", HOTLIST_EXPORT, &dialog_saveas },
+ { "Hotlist.Expand", TREE_EXPAND_ALL, 0 },
+ { "Hotlist.Expand.All", TREE_EXPAND_ALL, 0 },
+ { "Hotlist.Expand.Folders", TREE_EXPAND_FOLDERS, 0 },
+ { "Hotlist.Expand.Links", TREE_EXPAND_LINKS, 0 },
+ { "Hotlist.Collapse", TREE_COLLAPSE_ALL, 0 },
+ { "Hotlist.Collapse.All", TREE_COLLAPSE_ALL, 0 },
+ { "Hotlist.Collapse.Folders", TREE_COLLAPSE_FOLDERS, 0 },
+ { "Hotlist.Collapse.Links", TREE_COLLAPSE_LINKS, 0 },
+ { "Hotlist.Toolbars", NO_ACTION, 0 },
+ { "_Hotlist.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 },
+ { "Hotlist.Toolbars.EditToolbar", TOOLBAR_EDIT, 0 },
+ { "Selection", TREE_SELECTION, 0 },
+ { "Selection.Edit", TREE_SELECTION_EDIT, 0 },
+ { "Selection.Launch", TREE_SELECTION_LAUNCH, 0 },
+ { "Selection.Delete", TREE_SELECTION_DELETE, 0 },
+ { "SelectAll", TREE_SELECT_ALL, 0 },
+ { "Clear", TREE_CLEAR_SELECTION, 0 },
+ {NULL, 0, 0}
}
- tree_initialise(hotlist_tree);
- } else {
- fclose(fp);
- hotlist_tree = options_load_tree(option_hotlist_path);
- }
- if (!hotlist_tree) return;
- hotlist_tree->handle = (int)hotlist_window;
- hotlist_tree->movable = true;
- ro_gui_wimp_event_set_user_data(hotlist_window, hotlist_tree);
- ro_gui_wimp_event_register_keypress(hotlist_window,
- ro_gui_tree_keypress);
+ };
- /* Create our toolbar
- */
- hotlist_tree->toolbar = ro_gui_theme_create_toolbar(NULL,
- THEME_HOTLIST_TOOLBAR);
- if (hotlist_tree->toolbar)
- ro_gui_theme_attach_toolbar(hotlist_tree->toolbar,
- hotlist_window);
+ hotlist_window.menu = ro_gui_menu_define_menu(&hotlist_definition);
+
+ ro_gui_wimp_event_register_window_menu(hotlist_window.window,
+ hotlist_window.menu, ro_gui_hotlist_menu_prepare,
+ ro_gui_hotlist_menu_select, NULL,
+ ro_gui_hotlist_menu_warning, false);
}
/**
- * Perform a save to the default file
+ * Open the hotlist window.
+ *
*/
-void ro_gui_hotlist_save(void)
+
+void ro_gui_hotlist_open(void)
{
- os_error *error;
+ tree_set_redraw(ro_treeview_get_tree(hotlist_window.tv), true);
- if (!hotlist_tree)
- return;
+ if (!ro_gui_dialog_open_top(hotlist_window.window,
+ hotlist_window.toolbar, 600, 800)) {
- /* Save to our file
- */
- options_save_tree(hotlist_tree, option_hotlist_save,
- "NetSurf hotlist");
- error = xosfile_set_type(option_hotlist_save, 0xfaf);
- if (error)
- LOG(("xosfile_set_type: 0x%x: %s",
- error->errnum, error->errmess));
+ xwimp_set_caret_position(hotlist_window.window, -1, -100, -100, 32, -1);
+// \todo ro_gui_theme_process_toolbar(hotlist_window.toolbar, -1);
+ ro_treeview_set_origin(hotlist_window.tv, 0,
+ -(ro_gui_theme_toolbar_height(
+ hotlist_window.toolbar)));
+// ro_gui_tree_stop_edit(tree);
+//
+// if (tree->root->child) {
+// tree_set_node_selected(tree, tree->root, false);
+// tree_handle_node_changed(tree, tree->root,
+// false, true);
+// }
+ }
}
-
/**
- * Respond to a mouse click
+ * Prepare the hotlist menu for opening
*
- * \param pointer the pointer state
+ * \param window The window owning the menu.
+ * \param *menu The menu about to be opened.
*/
-bool ro_gui_hotlist_click(wimp_pointer *pointer)
+
+void ro_gui_hotlist_menu_prepare(wimp_w window, wimp_menu *menu)
{
- ro_gui_tree_click(pointer, hotlist_tree);
- if (pointer->buttons == wimp_CLICK_MENU)
- ro_gui_menu_create(hotlist_menu, pointer->pos.x,
- pointer->pos.y, pointer->w);
- else
- ro_gui_menu_prepare_action(pointer->w, TREE_SELECTION, false);
- return true;
-}
+ bool selection;
+ selection = ro_treeview_has_selection(hotlist_window.tv);
+ ro_gui_menu_set_entry_shaded(hotlist_window.menu, TREE_SELECTION,
+ !selection);
+ ro_gui_menu_set_entry_shaded(hotlist_window.menu, TREE_CLEAR_SELECTION,
+ !selection);
+
+ ro_gui_menu_set_entry_shaded(hotlist_window.menu, TOOLBAR_BUTTONS,
+ (hotlist_window.toolbar == NULL ||
+ hotlist_window.toolbar->editor));
+ ro_gui_menu_set_entry_ticked(hotlist_window.menu, TOOLBAR_BUTTONS,
+ (hotlist_window.toolbar != NULL &&
+ (hotlist_window.toolbar->display_buttons ||
+ hotlist_window.toolbar->editor)));
+
+ ro_gui_menu_set_entry_shaded(hotlist_window.menu, TOOLBAR_EDIT,
+ hotlist_window.toolbar == NULL);
+ ro_gui_menu_set_entry_ticked(hotlist_window.menu, TOOLBAR_EDIT,
+ (hotlist_window.toolbar != NULL &&
+ hotlist_window.toolbar->editor));
+
+ ro_gui_save_prepare(GUI_SAVE_HOTLIST_EXPORT_HTML,
+ NULL, NULL, NULL, NULL);
+}
+
/**
- * Informs the hotlist that some content has been visited
+ * Handle submenu warnings for the hotlist menu
*
- * \param content the content visited
+ * \param window The window owning the menu.
+ * \param *menu The menu to which the warning applies.
+ * \param *selection The wimp menu selection data.
+ * \param action The selected menu action.
*/
-void hotlist_visited(hlcache_handle *c)
+
+void ro_gui_hotlist_menu_warning(wimp_w window, wimp_menu *menu,
+ wimp_selection *selection, menu_action action)
{
- if ((!c) || (!content_get_url(c)) || (!hotlist_tree))
- return;
- ro_gui_hotlist_visited(c, hotlist_tree, hotlist_tree->root);
+ /* Do nothing */
}
-
/**
- * Informs the hotlist that some content has been visited
+ * Handle selections from the hotlist menu
*
- * \param content the content visited
- * \param tree the tree to find the URL data from
- * \param node the node to update siblings and children of
+ * \param window The window owning the menu.
+ * \param *menu The menu from which the selection was made.
+ * \param *selection The wimp menu selection data.
+ * \param action The selected menu action.
+ * \return true if action accepted; else false.
*/
-void ro_gui_hotlist_visited(hlcache_handle *c, struct tree *tree,
- struct node *node)
-{
- struct node_element *element;
- for (; node; node = node->next) {
- if (!node->folder) {
- element = tree_find_element(node, TREE_ELEMENT_URL);
- if ((element) && (!strcmp(element->text,
- content_get_url(c)))) {
- tree_update_URL_node(node, content_get_url(c),
- NULL);
- tree_handle_node_changed(tree, node, true,
- false);
- }
- }
- if (node->child)
- ro_gui_hotlist_visited(c, tree, node->child);
+bool ro_gui_hotlist_menu_select(wimp_w window, wimp_menu *menu,
+ wimp_selection *selection, menu_action action)
+{
+ switch (action) {
+ case HOTLIST_EXPORT:
+ ro_gui_dialog_open_persistent(window, dialog_saveas, true);
+ return true;
+ case TREE_NEW_FOLDER:
+ hotlist_add_folder();
+ return true;
+ case TREE_NEW_LINK:
+ hotlist_add_entry();
+ return true;
+ case TREE_EXPAND_ALL:
+ hotlist_expand_all();
+ return true;
+ case TREE_EXPAND_FOLDERS:
+ hotlist_expand_directories();
+ return true;
+ case TREE_EXPAND_LINKS:
+ hotlist_expand_addresses();
+ return true;
+ case TREE_COLLAPSE_ALL:
+ hotlist_collapse_all();
+ return true;
+ case TREE_COLLAPSE_FOLDERS:
+ hotlist_collapse_directories();
+ return true;
+ case TREE_COLLAPSE_LINKS:
+ hotlist_collapse_addresses();
+ return true;
+ case TREE_SELECTION_EDIT:
+ hotlist_edit_selected();
+ return true;
+ case TREE_SELECTION_LAUNCH:
+ hotlist_launch_selected();
+ return true;
+ case TREE_SELECTION_DELETE:
+ hotlist_delete_selected();
+ return true;
+ case TREE_SELECT_ALL:
+ hotlist_select_all();
+ return true;
+ case TREE_CLEAR_SELECTION:
+ hotlist_clear_selection();
+ return true;
+ default:
+ return false;
}
+
+ return false;
}
+/**
+ * Update the theme details of the hotlist window.
+ */
+void ro_gui_hotlist_update_theme(void)
+{
+ ro_treeview_update_theme(hotlist_window.tv);
+}
+
/**
- * Prepares the folder dialog contents for a node
+ * Check if a particular window handle is the hotlist window
*
- * \param node the node to prepare the dialogue for, or NULL
+ * \param window The window in question
+ * \return true if this window is the hotlist
*/
-void ro_gui_hotlist_prepare_folder_dialog(struct node *node)
+bool ro_gui_hotlist_check_window(wimp_w window)
{
- const char *name;
- const char *title;
-
- dialog_folder_node = node;
- if (node) {
- title = messages_get("EditFolder");
- name = node->data.text;
- } else {
- title = messages_get("NewFolder");
- name = messages_get("Folder");
- }
- ro_gui_set_window_title(dialog_folder, title);
- ro_gui_set_icon_string(dialog_folder, ICON_FOLDER_NAME, name, true);
- ro_gui_wimp_event_memorise(dialog_folder);
+ if (hotlist_window.window == window)
+ return true;
+ else
+ return false;
}
-
/**
- * Prepares the entry dialog contents for a node
+ * Check if a particular menu handle is the hotlist menu
*
- * \param node the node to prepare the dialogue for, or NULL
+ * \param *menu The menu in question.
+ * \return true if this menu is the hotlist menu
*/
-void ro_gui_hotlist_prepare_entry_dialog(struct node *node)
-{
- struct node_element *element;
- const char *name;
- const char *title;
- const char *url = "";
- dialog_entry_node = node;
- if (node) {
- title = messages_get("EditLink");
- name = node->data.text;
- if ((element = tree_find_element(node, TREE_ELEMENT_URL)))
- url = element->text;
- } else {
- title = messages_get("NewLink");
- name = messages_get("Link");
- }
- ro_gui_set_window_title(dialog_entry, title);
- ro_gui_set_icon_string(dialog_entry, ICON_ENTRY_NAME, name, true);
- ro_gui_set_icon_string(dialog_entry, ICON_ENTRY_URL, url, true);
- ro_gui_wimp_event_memorise(dialog_entry);
+bool ro_gui_hotlist_check_menu(wimp_menu *menu)
+{
+ if (hotlist_window.menu == menu)
+ return true;
+ else
+ return false;
}
-
+#if 0
/**
- * Apply the settings of dialog window (folder/entry edit)
+ * Handle URL dropped on hotlist
*
- * \param w the window to apply
+ * \param message the wimp message we're acting on
+ * \param url the URL to add
*/
-bool ro_gui_hotlist_dialog_apply(wimp_w w)
+void ro_gui_hotlist_url_drop(wimp_message *message, const char *url)
{
- struct node_element *element;
- struct node *node;
- const char *icon;
- char *title;
- char *url = NULL;
- url_func_result res;
- const struct url_data *data;
+ int x, y;
+ if (hotlist_window.window != message->data.data_xfer.w)
+ return;
- /* get our data */
- if (w == dialog_entry) {
- icon = ro_gui_get_icon_string(w, ICON_ENTRY_URL);
-
- res = url_normalize(icon, &url);
- if (res != URL_FUNC_OK) {
- warn_user(res == URL_FUNC_FAILED ? "NoURLError"
- : "NoMemory", 0);
- return false;
- }
-
- icon = ro_gui_get_icon_string(w, ICON_ENTRY_NAME);
- while (isspace(*icon))
- icon++;
- title = strdup(icon);
-
- node = dialog_entry_node;
- } else {
- icon = ro_gui_get_icon_string(w, ICON_FOLDER_NAME);
- while (isspace(*icon))
- icon++;
- title = strdup(icon);
-
- node = dialog_folder_node;
- }
-
- if (title != NULL)
- strip(title);
-
- /* check for lack of text */
- if (title == NULL || title[0] == '\0') {
- if (title == NULL)
- warn_user("NoMemory", 0);
- else if (title[0] == '\0')
- warn_user("NoNameError", 0);
- free(url);
- free(title);
- node = NULL;
- return false;
- }
- ro_gui_set_icon_string(w, url ? ICON_ENTRY_NAME : ICON_FOLDER_NAME,
- title, false);
-
- /* update/insert our data */
- if (!node) {
- if (url) {
- data = urldb_get_url_data(url);
- if (!data) {
- urldb_add_url(url);
- urldb_set_url_persistence(url, true);
- data = urldb_get_url_data(url);
- }
- if (!data) {
- free(url);
- free(title);
- return false;
- }
- if (!data->title)
- urldb_set_url_title(url, title);
- node = dialog_entry_node = tree_create_URL_node(
- hotlist_tree->root, url, data, title);
-
- } else {
- node = dialog_folder_node = tree_create_folder_node(
- hotlist_tree->root, title);
- }
- free(url);
- free(title);
- if (!node) {
- warn_user("NoMemory", 0);
- return false;
- }
- tree_handle_node_changed(hotlist_tree, node, true, false);
- ro_gui_tree_scroll_visible(hotlist_tree, &node->data);
- tree_redraw_area(hotlist_tree, node->box.x - NODE_INSTEP,
- 0, NODE_INSTEP, 16384);
- } else {
- element = tree_find_element(node, TREE_ELEMENT_URL);
- if (element) {
- free((void *)element->text);
- element->text = url;
- ro_gui_set_icon_string(w, ICON_ENTRY_URL, url, true);
- }
- free((void *)node->data.text);
- node->data.text = title;
- tree_handle_node_changed(hotlist_tree, node, true, false);
- }
- return true;
+ ro_gui_tree_get_tree_coordinates(hotlist_window.tree,
+ message->data.data_xfer.pos.x,
+ message->data.data_xfer.pos.y,
+ &x, &y);
+ hotlist_add_page_xy(url, x, y);
}
+#endif
+
Index: riscos/textselection.c
===================================================================
--- riscos/textselection.c (revision 10834)
+++ riscos/textselection.c (working copy)
@@ -183,7 +183,8 @@
if (ro_gui_window_to_window_pos(g, drag->final.x0, drag->final.y0, &pos))
browser_window_mouse_drag_end(g->bw,
- ro_gui_mouse_click_state(pointer.buttons),
+ ro_gui_mouse_click_state(pointer.buttons,
+ wimp_BUTTON_CLICK_DRAG),
pos.x, pos.y);
}
@@ -542,8 +543,8 @@
int box_x = 0;
int box_y = 0;
- /* with autoscrolling, we will probably need to remember the
- * gui_window and override the drag->w window handle which
+ /* with autoscrolling, we will probably need to remember the
+ * gui_window and override the drag->w window handle which
* could be any window on the desktop */
g = ro_gui_window_lookup(drag->w);
@@ -566,14 +567,14 @@
html_get_box_tree(h)) {
struct box *box = html_get_box_tree(h);
- while ((box = box_at_point(box, pos.x, pos.y,
+ while ((box = box_at_point(box, pos.x, pos.y,
&box_x, &box_y, &h))) {
- if (box->style &&
- css_computed_visibility(box->style) ==
+ if (box->style &&
+ css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN)
continue;
- if (box->gadget &&
+ if (box->gadget &&
box->gadget->type == GADGET_TEXTAREA) {
textarea = box;
gadget_box_x = box_x;
@@ -594,10 +595,10 @@
gui_window_set_pointer(g, GUI_POINTER_CARET);
text_box = textarea_get_position(textarea, pos.x - gadget_box_x,
- pos.y - gadget_box_y,
+ pos.y - gadget_box_y,
&char_offset, &pixel_offset);
- caret_set_position(&ghost_caret, bw, text_box,
+ caret_set_position(&ghost_caret, bw, text_box,
char_offset, pixel_offset);
drag_claimed = true;
@@ -613,16 +614,16 @@
wimp_full_message_drag_claim claim;
os_error *error;
- claim.size =
+ claim.size =
offsetof(wimp_full_message_drag_claim, file_types) + 8;
claim.your_ref = drag->my_ref;
claim.action = message_DRAG_CLAIM;
- claim.flags = wimp_DRAG_CLAIM_POINTER_CHANGED |
+ claim.flags = wimp_DRAG_CLAIM_POINTER_CHANGED |
wimp_DRAG_CLAIM_SUPPRESS_DRAGBOX;
claim.file_types[0] = osfile_TYPE_TEXT;
claim.file_types[1] = ~0;
- error = xwimp_send_message(wimp_USER_MESSAGE,
+ error = xwimp_send_message(wimp_USER_MESSAGE,
(wimp_message *) &claim, drag->sender);
if (error) {
LOG(("xwimp_send_message: 0x%x: %s",
Index: riscos/cookies.c
===================================================================
--- riscos/cookies.c (revision 10834)
+++ riscos/cookies.c (working copy)
@@ -1,5 +1,6 @@
/*
* Copyright 2006 Richard Wilson <info(a)tinct.net>
+ * Copyright 2010 Stephen Fryatt <stevef(a)netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -44,174 +45,243 @@
#include "utils/url.h"
#include "utils/utils.h"
-static bool ro_gui_cookies_click(wimp_pointer *pointer);
-static struct node *ro_gui_cookies_find(const char *url);
+static void ro_gui_cookies_menu_prepare(wimp_w window, wimp_menu *menu);
+static bool ro_gui_cookies_menu_select(wimp_w window, wimp_menu *menu,
+ wimp_selection *selection, menu_action action);
+static void ro_gui_cookies_menu_warning(wimp_w window, wimp_menu *menu,
+ wimp_selection *selection, menu_action action);
-/* The history window, toolbar and plot origins */
-static wimp_w cookies_window;
-struct tree *cookies_tree;
-static bool cookies_init;
+/* The RISC OS cookie window, toolbar and treeview data. */
+static struct ro_cookies_window {
+ wimp_w window;
+ struct toolbar *toolbar;
+ ro_treeview *tv;
+ wimp_menu *menu;
+} cookies_window;
+
/**
- * Initialise cookies tree
+ * Pre-Initialise the cookies tree. This is called for things that
+ * need to be done at the gui_init() stage, such as loading templates.
*/
-void ro_gui_cookies_initialise(void)
+
+void ro_gui_cookies_preinitialise(void)
{
- /* create our window */
- cookies_window = ro_gui_dialog_create("tree");
- ro_gui_set_window_title(cookies_window,
+ /* Create our window. */
+
+ cookies_window.window = ro_gui_dialog_create("tree");
+ ro_gui_set_window_title(cookies_window.window,
messages_get("Cookies"));
- ro_gui_wimp_event_register_redraw_window(cookies_window,
- ro_gui_tree_redraw);
- ro_gui_wimp_event_register_open_window(cookies_window,
- ro_gui_tree_open);
- ro_gui_wimp_event_register_mouse_click(cookies_window,
- ro_gui_cookies_click);
+}
- /* Create an empty tree */
- cookies_tree = calloc(sizeof(struct tree), 1);
- if (!cookies_tree) {
- warn_user("NoMemory", 0);
+/**
+ * Initialise cookies tree, at the gui_init2() stage.
+ */
+
+void ro_gui_cookies_postinitialise(void)
+{
+ /* Create our toolbar. */
+
+ cookies_window.toolbar = ro_gui_theme_create_toolbar(NULL,
+ THEME_COOKIES_TOOLBAR);
+ if (cookies_window.toolbar)
+ ro_gui_theme_attach_toolbar(cookies_window.toolbar,
+ cookies_window.window);
+
+ /* Create the treeview with the window and toolbar. */
+
+ cookies_window.tv = ro_treeview_create(cookies_window.window,
+ cookies_window.toolbar, cookies_get_tree_flags());
+ if (cookies_window.tv == NULL) {
+ LOG(("Failed to allocate treeview"));
return;
}
- cookies_tree->root = tree_create_folder_node(NULL, "Root");
- if (!cookies_tree->root) {
- warn_user("NoMemory", 0);
- free(cookies_tree);
- cookies_tree = NULL;
- return;
- }
- cookies_tree->root->expanded = true;
- cookies_tree->handle = (int)cookies_window;
- cookies_tree->movable = false;
- cookies_tree->no_drag = true;
- ro_gui_wimp_event_set_user_data(cookies_window,
- cookies_tree);
- ro_gui_wimp_event_register_keypress(cookies_window,
- ro_gui_tree_keypress);
- /* Create our toolbar */
- cookies_tree->toolbar = ro_gui_theme_create_toolbar(NULL,
- THEME_COOKIES_TOOLBAR);
- if (cookies_tree->toolbar)
- ro_gui_theme_attach_toolbar(cookies_tree->toolbar,
- cookies_window);
+ /* Initialise the cookies into the tree. */
- cookies_init = true;
- urldb_iterate_cookies(cookies_update);
- cookies_init = false;
- tree_initialise(cookies_tree);
+ cookies_initialise(ro_treeview_get_tree(cookies_window.tv));
+
+
+ /* Build the cookies window menu. */
+
+ static const struct ns_menu cookies_definition = {
+ "Cookies", {
+ { "Cookies", NO_ACTION, 0 },
+ { "Cookies.Expand", TREE_EXPAND_ALL, 0 },
+ { "Cookies.Expand.All", TREE_EXPAND_ALL, 0 },
+ { "Cookies.Expand.Folders", TREE_EXPAND_FOLDERS, 0 },
+ { "Cookies.Expand.Links", TREE_EXPAND_LINKS, 0 },
+ { "Cookies.Collapse", TREE_COLLAPSE_ALL, 0 },
+ { "Cookies.Collapse.All", TREE_COLLAPSE_ALL, 0 },
+ { "Cookies.Collapse.Folders", TREE_COLLAPSE_FOLDERS, 0 },
+ { "Cookies.Collapse.Links", TREE_COLLAPSE_LINKS, 0 },
+ { "Cookies.Toolbars", NO_ACTION, 0 },
+ { "_Cookies.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 },
+ { "Cookies.Toolbars.EditToolbar",TOOLBAR_EDIT, 0 },
+ { "Selection", TREE_SELECTION, 0 },
+ { "Selection.Delete", TREE_SELECTION_DELETE, 0 },
+ { "SelectAll", TREE_SELECT_ALL, 0 },
+ { "Clear", TREE_CLEAR_SELECTION, 0 },
+ {NULL, 0, 0}
+ }
+ };
+ cookies_window.menu = ro_gui_menu_define_menu(&cookies_definition);
+
+ ro_gui_wimp_event_register_window_menu(cookies_window.window,
+ cookies_window.menu, ro_gui_cookies_menu_prepare,
+ ro_gui_cookies_menu_select, NULL,
+ ro_gui_cookies_menu_warning, false);
}
+/**
+ * \TODO - Open the cookies window.
+ *
+ */
+void ro_gui_cookies_open(void)
+{
+ tree_set_redraw(ro_treeview_get_tree(cookies_window.tv), true);
+
+ if (!ro_gui_dialog_open_top(cookies_window.window,
+ cookies_window.toolbar, 600, 800)) {
+ ro_treeview_set_origin(cookies_window.tv, 0,
+ -(ro_gui_theme_toolbar_height(
+ cookies_window.toolbar)));
+ }
+}
+
/**
- * Respond to a mouse click
+ * Prepare the cookies menu for opening
*
- * \param pointer the pointer state
- * \return true to indicate click handled
+ * \param window The window owning the menu.
+ * \param *menu The menu about to be opened.
*/
-bool ro_gui_cookies_click(wimp_pointer *pointer)
+
+void ro_gui_cookies_menu_prepare(wimp_w window, wimp_menu *menu)
{
- ro_gui_tree_click(pointer, cookies_tree);
- if (pointer->buttons == wimp_CLICK_MENU)
- ro_gui_menu_create(cookies_menu, pointer->pos.x,
- pointer->pos.y, pointer->w);
- else
- ro_gui_menu_prepare_action(pointer->w, TREE_SELECTION, false);
- return true;
+ bool selection;
+
+ selection = ro_treeview_has_selection(cookies_window.tv);
+
+ ro_gui_menu_set_entry_shaded(cookies_window.menu, TREE_SELECTION,
+ !selection);
+ ro_gui_menu_set_entry_shaded(cookies_window.menu, TREE_CLEAR_SELECTION,
+ !selection);
+
+ ro_gui_menu_set_entry_shaded(cookies_window.menu, TOOLBAR_BUTTONS,
+ (cookies_window.toolbar == NULL ||
+ cookies_window.toolbar->editor));
+ ro_gui_menu_set_entry_ticked(cookies_window.menu, TOOLBAR_BUTTONS,
+ (cookies_window.toolbar != NULL &&
+ (cookies_window.toolbar->display_buttons ||
+ (cookies_window.toolbar->editor))));
+
+ ro_gui_menu_set_entry_shaded(cookies_window.menu, TOOLBAR_EDIT,
+ cookies_window.toolbar == NULL);
+ ro_gui_menu_set_entry_ticked(cookies_window.menu, TOOLBAR_EDIT,
+ (cookies_window.toolbar != NULL &&
+ cookies_window.toolbar->editor));
}
+/**
+ * Handle submenu warnings for the cookies menu
+ *
+ * \param window The window owning the menu.
+ * \param *menu The menu to which the warning applies.
+ * \param *selection The wimp menu selection data.
+ * \param action The selected menu action.
+ */
+void ro_gui_cookies_menu_warning(wimp_w window, wimp_menu *menu,
+ wimp_selection *selection, menu_action action)
+{
+ /* Do nothing */
+}
+
/**
- * Perform cookie addition
+ * Handle selections from the cookies menu
*
- * \param data Cookie data for a domain, or NULL
- * \return true (for urldb_iterate_entries)
+ * \param window The window owning the menu.
+ * \param *menu The menu from which the selection was made.
+ * \param *selection The wimp menu selection data.
+ * \param action The selected menu action.
+ * \return true if action accepted; else false.
*/
-bool cookies_update(const char *domain, const struct cookie_data *data)
+
+bool ro_gui_cookies_menu_select(wimp_w window, wimp_menu *menu,
+ wimp_selection *selection, menu_action action)
{
- struct node *parent;
- struct node *node = NULL;
- struct node *child;
- struct node *add;
- const struct cookie_data *cookie = NULL;
- bool expanded;
+ switch (action) {
+ case TREE_EXPAND_ALL:
+ cookies_expand_all();
+ return true;
+ case TREE_EXPAND_FOLDERS:
+ cookies_expand_domains();
+ return true;
+ case TREE_EXPAND_LINKS:
+ cookies_expand_cookies();
+ return true;
+ case TREE_COLLAPSE_ALL:
+ cookies_collapse_all();
+ return true;
+ case TREE_COLLAPSE_FOLDERS:
+ cookies_collapse_domains();
+ return true;
+ case TREE_COLLAPSE_LINKS:
+ cookies_collapse_cookies();
+ return true;
+ case TREE_SELECTION_DELETE:
+ cookies_delete_selected();
+ return true;
+ case TREE_SELECT_ALL:
+ cookies_select_all();
+ return true;
+ case TREE_CLEAR_SELECTION:
+ cookies_clear_selection();
+ return true;
+ default:
+ return false;
+ }
- assert(domain);
+ return false;
+}
- /* check if we're a domain, and add get the first cookie */
- if (data)
- for (cookie = data; cookie->prev; cookie = cookie->prev);
+/**
+ * Update the theme details of the cookies window.
+ */
- if (!cookies_init) {
- node = ro_gui_cookies_find(domain);
- if (node) {
- /* mark as deleted so we don't remove the cookies */
- expanded = node->expanded;
- for (child = node->child; child; child = child->next)
- child->deleted = true;
- if (node->child)
- tree_delete_node(cookies_tree, node->child,
- true);
- /* deleting will have contracted our node */
- node->expanded = expanded;
- }
- if (!data) {
- if (!node)
- return true;
- tree_delete_node(cookies_tree, node, false);
- tree_handle_node_changed(cookies_tree,
- cookies_tree->root, true, false);
- return true;
- }
- }
+void ro_gui_cookies_update_theme(void)
+{
+ ro_treeview_update_theme(cookies_window.tv);
+}
- if (!node) {
- for (parent = cookies_tree->root->child; parent;
- parent = parent->next) {
- if (strcmp(domain, parent->data.text) == 0)
- break;
- }
- if (!parent) {
- node = tree_create_folder_node(cookies_tree->root,
- domain);
- } else {
- node = parent;
- }
- }
- if (!node)
+/**
+ * Check if a particular window handle is the cookies window
+ *
+ * \param window the window in question
+ * \return true if this window is the cookies
+ */
+
+bool ro_gui_cookies_check_window(wimp_w window)
+{
+/* SF if (cookies_window.w == window)
return true;
- node->editable = false;
-
- for (; cookie; cookie = cookie->next) {
- add = tree_create_cookie_node(node, cookie);
- if (add && !cookies_init)
- tree_handle_node_changed(cookies_tree, add,
- true, false);
- }
- if (!cookies_init) {
- tree_handle_node_changed(cookies_tree, node,
- true, false);
- tree_redraw_area(cookies_tree,
- node->box.x - NODE_INSTEP,
- 0, NODE_INSTEP, 16384);
- }
- return true;
+ else*/
+ return false;
}
/**
- * Find an entry in the cookie tree
+ * Check if a particular menu handle is the cookies menu
*
- * \param url The URL to find
- * \return Pointer to node, or NULL if not found
+ * \param *menu The menu in question.
+ * \return true if this menu is the cookies menu
*/
-struct node *ro_gui_cookies_find(const char *url)
+
+bool ro_gui_cookies_check_menu(wimp_menu *menu)
{
- struct node *node;
+ if (cookies_window.menu == menu)
+ return true;
+ else
+ return false;
+}
- for (node = cookies_tree->root->child; node; node = node->next) {
- if (!strcmp(url, node->data.text))
- return node;
- }
- return NULL;
-}
Index: riscos/cookies.h
===================================================================
--- riscos/cookies.h (revision 10834)
+++ riscos/cookies.h (working copy)
@@ -1,5 +1,6 @@
/*
* Copyright 2006 Richard Wilson <info(a)tinct.net>
+ * Copyright 2010 Stephen Fryatt <stevef(a)netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -23,6 +24,13 @@
#ifndef _NETSURF_RISCOS_COOKIES_H_
#define _NETSURF_RISCOS_COOKIES_H_
-void ro_gui_cookies_initialise(void);
+void ro_gui_cookies_preinitialise(void);
+void ro_gui_cookies_postinitialise(void);
+bool ro_gui_cookies_check_window(wimp_w window);
+bool ro_gui_cookies_check_menu(wimp_menu *menu);
+void ro_gui_cookies_open(void);
+void ro_gui_cookies_update_theme(void);
+
#endif
+
Index: riscos/gui.c
===================================================================
--- riscos/gui.c (revision 10834)
+++ riscos/gui.c (working copy)
@@ -55,20 +55,26 @@
#include "content/content.h"
#include "content/hlcache.h"
#include "content/urldb.h"
+#include "desktop/cookies.h"
#include "desktop/gui.h"
+#include "desktop/history_global_core.h"
+#include "desktop/hotlist.h"
#include "desktop/netsurf.h"
#include "desktop/options.h"
#include "desktop/save_complete.h"
#include "desktop/tree.h"
+#include "desktop/tree_url_node.h"
#include "render/box.h"
#include "render/font.h"
#include "render/html.h"
#include "riscos/bitmap.h"
#include "riscos/buffer.h"
+#include "riscos/cookies.h"
#include "riscos/dialog.h"
#include "riscos/global_history.h"
#include "riscos/gui.h"
#include "riscos/help.h"
+#include "riscos/hotlist.h"
#include "riscos/menus.h"
#include "riscos/message.h"
#include "riscos/options.h"
@@ -78,6 +84,7 @@
#include "riscos/print.h"
#include "riscos/query.h"
#include "riscos/save.h"
+#include "riscos/sslcert.h"
#include "riscos/textselection.h"
#include "riscos/theme.h"
#include "riscos/treeview.h"
@@ -184,7 +191,7 @@
} prev_sigs;
/** Accepted wimp user messages. */
-static ns_wimp_message_list task_messages = {
+static ns_wimp_message_list task_messages = {
message_HELP_REQUEST,
{
message_DATA_SAVE,
@@ -347,6 +354,8 @@
option_theme_path = strdup("NetSurf:Themes");
if (!option_theme_save)
option_theme_save = strdup(CHOICES_PREFIX "Themes");
+ if (!option_tree_icons_dir)
+ option_tree_icons_dir = strdup("NetSurf:Resources.Icons");
if (!option_theme || ! option_toolbar_browser ||
!option_toolbar_hotlist || !option_toolbar_history ||
@@ -355,7 +364,7 @@
!option_url_save || !option_hotlist_path ||
!option_hotlist_save || !option_recent_path ||
!option_recent_save || !option_theme_path ||
- !option_theme_save)
+ !option_theme_save || !option_tree_icons_dir)
die("Failed initialising string options");
/* Create our choices directories */
@@ -394,7 +403,7 @@
default_stylesheet_url = strdup("file:///NetSurf:/Resources/CSS");
quirks_stylesheet_url = strdup("file:///NetSurf:/Resources/Quirks");
adblock_stylesheet_url = strdup("file:///NetSurf:/Resources/AdBlock");
- if (!default_stylesheet_url || !quirks_stylesheet_url ||
+ if (!default_stylesheet_url || !quirks_stylesheet_url ||
!adblock_stylesheet_url)
die("Failed initialising string constants.");
@@ -479,9 +488,6 @@
/* Done with the templates file */
wimp_close_template();
- /* Initialise tree views (must be after UI sprites are loaded) */
- ro_gui_tree_initialise();
-
/* Create Iconbar icon */
ro_gui_icon_bar_create();
@@ -670,6 +676,21 @@
char *url = 0;
bool open_window = option_open_browser_at_startup;
+ /* Complete initialisation of the treeview modules. */
+
+ /* certificate verification window */
+ ro_gui_cert_postinitialise();
+
+ /* hotlist window */
+ ro_gui_hotlist_postinitialise();
+
+ /* global history window */
+ ro_gui_global_history_postinitialise();
+
+ /* cookies window */
+ ro_gui_cookies_postinitialise();
+
+
/* parse command-line arguments */
if (argc == 2) {
LOG(("parameters: '%s'", argv[1]));
@@ -781,8 +802,9 @@
urldb_save_cookies(option_cookie_jar);
urldb_save(option_url_save);
ro_gui_window_quit();
- ro_gui_global_history_save();
- ro_gui_hotlist_save();
+ history_global_cleanup();
+ cookies_cleanup();
+ hotlist_cleanup(option_hotlist_save);
ro_gui_saveas_quit();
rufl_quit();
free(gui_sprites);
@@ -1109,6 +1131,9 @@
// break;
default:
+ if (ro_gui_hotlist_check_window(gui_track_wimp_w))
+ ro_treeview_mouse_at(gui_track_wimp_w,
+ &pointer);
if (gui_track_wimp_w == history_window)
ro_gui_history_mouse_at(&pointer);
if (gui_track_wimp_w == dialog_url_complete)
@@ -1203,8 +1228,10 @@
default:
gui_track_wimp_w = entering->w;
gui_track_gui_window = ro_gui_window_lookup(entering->w);
- gui_track = gui_track_gui_window || gui_track_wimp_w == history_window ||
- gui_track_wimp_w == dialog_url_complete;
+ gui_track = gui_track_gui_window ||
+ gui_track_wimp_w == history_window ||
+ gui_track_wimp_w == dialog_url_complete ||
+ ro_gui_hotlist_check_window(gui_track_wimp_w);
break;
}
}
@@ -1275,11 +1302,11 @@
break;
case GUI_DRAG_TREE_SELECT:
- ro_gui_tree_selection_drag_end(drag);
+// ro_gui_tree_selection_drag_end(drag);
break;
case GUI_DRAG_TREE_MOVE:
- ro_gui_tree_move_drag_end(drag);
+// ro_gui_tree_move_drag_end(drag);
break;
case GUI_DRAG_TOOLBAR_CONFIG:
@@ -1485,12 +1512,7 @@
char *url = 0;
char *title = NULL;
struct gui_window *g;
- struct node *node;
- struct node *link;
os_error *error;
- int x, y;
- bool before;
- const struct url_data *data;
g = ro_gui_window_lookup(message->data.data_xfer.w);
if (g) {
@@ -1551,28 +1573,9 @@
if (g) {
browser_window_go(g->bw, url, 0, true);
- } else if ((hotlist_tree) && ((wimp_w)hotlist_tree->handle ==
- message->data.data_xfer.w)) {
- data = urldb_get_url_data(url);
- if (!data) {
- urldb_add_url(url);
- urldb_set_url_persistence(url, true);
- data = urldb_get_url_data(url);
- }
- if (data) {
- ro_gui_tree_get_tree_coordinates(hotlist_tree,
- message->data.data_xfer.pos.x,
- message->data.data_xfer.pos.y,
- &x, &y);
- link = tree_get_link_details(hotlist_tree, x, y, &before);
- node = tree_create_URL_node(NULL, url, data, title);
- tree_link_node(link, node, before);
- tree_handle_node_changed(hotlist_tree, node, false, true);
- tree_redraw_area(hotlist_tree, node->box.x - NODE_INSTEP, 0,
- NODE_INSTEP, 16384);
- if ((!title) && (!data->title))
- ro_gui_tree_start_edit(hotlist_tree, &node->data, NULL);
- }
+// } else if (ro_gui_hotlist_check_window(message->data.data_xfer.w)) {
+// /* Drop URL into hotlist */
+// ro_gui_hotlist_url_drop(message, url);
} else {
browser_window_create(url, 0, 0, true, false);
}
Index: riscos/gui.h
===================================================================
--- riscos/gui.h (revision 10834)
+++ riscos/gui.h (working copy)
@@ -64,7 +64,6 @@
extern osspriteop_area *gui_sprites;
extern bool dialog_folder_add, dialog_entry_add, hotlist_insert;
extern bool print_active, print_text_black;
-extern struct tree *hotlist_tree, *global_history_tree, *cookies_tree;
typedef enum { GUI_DRAG_NONE, GUI_DRAG_SELECTION, GUI_DRAG_DOWNLOAD_SAVE,
GUI_DRAG_SAVE, GUI_DRAG_SCROLL, GUI_DRAG_STATUS_RESIZE,
@@ -136,10 +135,6 @@
/* in 401login.c */
void ro_gui_401login_init(void);
-/* in sslcert.c */
-void ro_gui_cert_init(void);
-void ro_gui_cert_open(struct tree *tree, struct node *node);
-
/* in window.c */
void ro_gui_window_quit(void);
/* void ro_gui_window_close_all(void); */
@@ -161,7 +156,10 @@
void ro_gui_window_default_options(struct browser_window *bw);
void ro_gui_window_redraw_all(void);
void ro_gui_window_prepare_navigate_all(void);
-browser_mouse_state ro_gui_mouse_click_state(wimp_mouse_state buttons);
+browser_mouse_state ro_gui_mouse_click_state(wimp_mouse_state buttons,
+ wimp_icon_flags type);
+browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons,
+ wimp_icon_flags type);
bool ro_gui_shift_pressed(void);
bool ro_gui_ctrl_pressed(void);
bool ro_gui_alt_pressed(void);
@@ -178,13 +176,6 @@
bool pointer);
void ro_gui_history_mouse_at(wimp_pointer *pointer);
-/* in hotlist.c */
-void ro_gui_hotlist_initialise(void);
-void ro_gui_hotlist_save(void);
-void ro_gui_hotlist_prepare_folder_dialog(struct node *node);
-void ro_gui_hotlist_prepare_entry_dialog(struct node *node);
-bool ro_gui_hotlist_dialog_apply(wimp_w w);
-
/* in filetype.c */
int ro_content_filetype(struct hlcache_handle *c);
int ro_content_filetype_from_type(content_type type);
Index: riscos/url_complete.c
===================================================================
--- riscos/url_complete.c (revision 10834)
+++ riscos/url_complete.c (working copy)
@@ -149,7 +149,7 @@
if (url_complete_matches) {
for (i = 0; i < MAXIMUM_VISIBLE_LINES; i++) {
if (i < lines) {
- url_complete_redraw[i] =
+ url_complete_redraw[i] =
url_complete_matches[i];
} else {
url_complete_redraw[i] = NULL;
@@ -726,15 +726,13 @@
ICON_TOOLBAR_URL,
url_complete_matches[
url_complete_matches_selection], true);
- global_history_add_recent(url_complete_matches[
- url_complete_matches_selection]);
/** \todo The interaction of components here is hideous */
/* Do NOT make any attempt to use any of the global url
* completion variables after this call to browser_window_go.
* They will be invalidated by (at least):
* + gui_window_set_url
- * + destruction of (i)frames within the current page
+ * + destruction of (i)frames within the current page
* Any attempt to use them will probably result in a crash.
*/
Index: riscos/treeview.c
===================================================================
--- riscos/treeview.c (revision 10834)
+++ riscos/treeview.c (working copy)
@@ -1,5 +1,6 @@
/*
* Copyright 2005 Richard Wilson <info(a)tinct.net>
+ * Copyright 2010 Stephen Fryatt <stevef(a)netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -20,6 +21,8 @@
* Generic tree handling (implementation).
*/
+#include <oslib/os.h>
+
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
@@ -35,7 +38,9 @@
#include "content/urldb.h"
#include "desktop/browser.h"
#include "desktop/plotters.h"
+#include "desktop/textinput.h"
#include "desktop/tree.h"
+#include "desktop/tree_url_node.h"
#include "riscos/bitmap.h"
#include "riscos/dialog.h"
#include "riscos/gui.h"
@@ -56,1379 +61,746 @@
#define wimp_KEY_END wimp_KEY_COPY
#endif
-#define TREE_EXPAND 0
-#define TREE_COLLAPSE 1
+/** \todo Ugh! */
+const char tree_directory_icon_name[] = "directory.png";
+const char tree_content_icon_name[] = "content.png";
+struct ro_treeview
+{
+ struct tree *tree; /*< Pointer to treeview tree block. */
+ wimp_w w; /*< RO Window Handle for tree window. */
+ struct toolbar *tb; /*< Pointer to toolbar block. */
+ struct {
+ int x; /*< X origin of tree, to RO work area. */
+ int y; /*< Y origin of tree, to RO work area. */
+ } origin;
+ struct {
+ int x; /*< X dimension of the tree, in RO units. */
+ int y; /*< Y dimension of the tree, in RO units. */
+ } size; /* (Dimensions are 0 until set correctly). */
+ struct {
+ int x; /*< X extent of the window, in RO units. */
+ int y; /*< Y extent of the window, in RO units. */
+ } extent; /* (Extents are 0 until set correctly). */
+ struct {
+ int x; /*< X coordinate of drag start */
+ int y; /*< Y coordinate of drag start */
+ } drag_start;
+ bool drag; /*< True if there's a drag going on */
+};
-static bool ro_gui_tree_initialise_sprite(const char *name, int number);
-static void ro_gui_tree_launch_selected_node(struct tree *tree, struct node *node, bool all);
-static bool ro_gui_tree_launch_node(struct tree *tree, struct node *node);
-static void tree_handle_node_changed_callback(void *p);
+static void ro_treeview_redraw_request(int x, int y, int width, int height,
+ void *pw);
+static void ro_treeview_resized(struct tree *tree, int width, int height,
+ void *pw);
+static void ro_treeview_scroll_visible(int y, int height, void *pw);
+static void ro_treeview_get_window_dimensions(int *width, int *height,
+ void *pw);
+static void ro_treeview_redraw(wimp_draw *redraw);
+static void ro_treeview_redraw_loop(wimp_draw *redraw, ro_treeview *tv,
+ osbool more);
+static void ro_treeview_open(wimp_open *open);
+static bool ro_treeview_mouse_click(wimp_pointer *pointer);
+static bool ro_treeview_keypress(wimp_key *key);
-/* an array of sprite addresses for Tinct */
-static char *ro_gui_tree_sprites[2];
+static void ro_treeview_set_window_extent(ro_treeview *tv,
+ int width, int height);
-/* origin adjustment */
-static int ro_gui_tree_origin_x;
-static int ro_gui_tree_origin_y;
-
-/* element drawing */
-static wimp_icon ro_gui_tree_icon;
-static char ro_gui_tree_icon_validation[24];
-static char ro_gui_tree_icon_null[] = "";
-
-/* dragging information */
-static struct tree *ro_gui_tree_current_drag_tree;
-static wimp_mouse_state ro_gui_tree_current_drag_buttons;
-
-/* editing information */
-static wimp_icon_create ro_gui_tree_edit_icon;
-
-/* dragging information */
-static char ro_gui_tree_drag_name[12];
-
-/* callback update */
-struct node_update {
- struct tree *tree;
- struct node *node;
+static const struct treeview_table ro_tree_callbacks = {
+ ro_treeview_redraw_request,
+ ro_treeview_resized,
+ ro_treeview_scroll_visible,
+ ro_treeview_get_window_dimensions
};
-
/**
- * Performs any initialisation for tree rendering
- */
-bool ro_gui_tree_initialise(void)
-{
- if (ro_gui_tree_initialise_sprite("expand", TREE_EXPAND) ||
- ro_gui_tree_initialise_sprite("collapse", TREE_COLLAPSE))
- return false;
-
- ro_gui_tree_edit_icon.icon.flags = wimp_ICON_TEXT | wimp_ICON_INDIRECTED |
- wimp_ICON_VCENTRED | wimp_ICON_FILLED | wimp_ICON_BORDER |
- (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT) |
- (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) |
- (wimp_BUTTON_WRITABLE << wimp_ICON_BUTTON_TYPE_SHIFT);
- ro_gui_tree_edit_icon.icon.data.indirected_text.validation =
- ro_gui_tree_icon_null;
- ro_gui_tree_edit_icon.icon.data.indirected_text.size = 256;
-
- return true;
-}
-
-
-/**
- * Initialise a sprite for use with Tinct
+ * Create a RISC OS GUI implementation of a treeview tree.
*
- * \param name the name of the sprite
- * \param number the sprite cache number
- * \return whether an error occurred during initialisation
- */
-bool ro_gui_tree_initialise_sprite(const char *name, int number)
-{
- char icon_name[12];
- const char *icon = icon_name;
- os_error *error;
-
- snprintf(icon_name, sizeof(icon_name), "tr_%s", name);
-
- error = xosspriteop_select_sprite(osspriteop_USER_AREA, gui_sprites,
- (osspriteop_id) icon,
- (osspriteop_header **) &ro_gui_tree_sprites[number]);
- if (error) {
- warn_user("MiscError", error->errmess);
- LOG(("Failed to find sprite 'tr_%s'", name));
- return true;
- }
-
- return false;
-}
-
-
-/**
- * Informs the current window manager that an area requires updating.
+ * \param window The window to create the tree in.
+ * \param *toolbar A toolbar to attach to the window.
+ * \param flags The treeview flags.
*
- * \param tree the tree that is requesting a redraw
- * \param x the x co-ordinate of the redraw area
- * \param y the y co-ordinate of the redraw area
- * \param width the width of the redraw area
- * \param height the height of the redraw area
+ * \return The RISC OS treeview pointer.
*/
-void tree_redraw_area(struct tree *tree, int x, int y, int width, int height)
+
+ro_treeview *ro_treeview_create(wimp_w window, struct toolbar *toolbar,
+ unsigned int flags)
{
- os_error *error;
+ ro_treeview *tv;
- assert(tree);
- assert(tree->handle);
+ /* Claim memory for the treeview block, and create a tree. */
- if (tree->toolbar)
- y += ro_gui_theme_toolbar_height(tree->toolbar);
- error = xwimp_force_redraw((wimp_w)tree->handle, tree->offset_x + x - 2,
- -tree->offset_y - y - height, tree->offset_x + x + width + 4,
- -tree->offset_y - y);
- if (error) {
- LOG(("xwimp_force_redraw: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("WimpError", error->errmess);
- }
-}
+ tv = malloc(sizeof(ro_treeview));
+ if (tv == NULL)
+ return NULL;
+ tv->w = window;
+ tv->tb = toolbar;
-/**
- * Draws a line.
- *
- * \param tree the tree to draw a line for
- * \param x the x co-ordinate
- * \param x the y co-ordinate
- * \param x the width of the line
- * \param x the height of the line
- */
-void tree_draw_line(int x, int y, int width, int height)
-{
- os_error *error;
- int y0, y1;
-
- /* stop the 16-bit co-ordinate system from causing redraw errors */
- y1 = ro_gui_tree_origin_y - y;
- if (y1 < 0)
- return;
- y0 = y1 - height;
- if (y0 > 16384)
- return;
- if (y0 < 0)
- y0 = 0;
- if (y1 > 16384)
- y1 = 16384;
-
- error = xcolourtrans_set_gcol((os_colour)0x88888800, 0, os_ACTION_OVERWRITE,
- 0, 0);
- if (error) {
- LOG(("xcolourtrans_set_gcol: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("MiscError", error->errmess);
- return;
+ tv->tree = tree_create(flags, &ro_tree_callbacks, tv);
+ if (tv->tree == NULL) {
+ free(tv);
+ return NULL;
}
- error = xos_plot(os_MOVE_TO, ro_gui_tree_origin_x + x, y0);
- if (!error)
- xos_plot(os_PLOT_TO, ro_gui_tree_origin_x + x + width, y1);
- if (error) {
- LOG(("xos_plot: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("MiscError", error->errmess);
- return;
- }
-}
+ /* Set the tree redraw origin at a default 0,0 RO units. */
-/**
- * Draws an element, including any expansion icons
- *
- * \param tree the tree to draw an element for
- * \param element the element to draw
- */
-void tree_draw_node_element(struct tree *tree, struct node_element *element)
-{
- os_error *error;
- int toolbar_height = 0;
- struct node_element *url_element;
- const struct bitmap *bitmap = NULL;
- struct node_update *update;
- const uint8_t *frame;
- rufl_code code;
- int x0, y0, x1, y1;
- bool selected = false;
- colour bg, c;
+ tv->origin.x = 0;
+ tv->origin.y = 0;
- assert(tree);
- assert(element);
- assert(element->parent);
+ /* Set the tree size as 0,0 to indicate that we don't know. */
- if (tree->toolbar)
- toolbar_height = ro_gui_theme_toolbar_height(tree->toolbar);
+ tv->size.x = 0;
+ tv->size.y = 0;
- x0 = ro_gui_tree_origin_x + element->box.x;
- x1 = x0 + element->box.width;
- y1 = ro_gui_tree_origin_y - element->box.y;
- y0 = y1 - element->box.height;
- if (&element->parent->data == element)
- if (element->parent->selected)
- selected = true;
+ /* Set the tree window extent to 0,0, to indicate that we
+ * don't know. */
+ tv->extent.x = 0;
+ tv->extent.y = 0;
- switch (element->type) {
- case NODE_ELEMENT_TEXT_PLUS_SPRITE:
- assert(element->sprite);
+ /* Set that there is no drag opperation at the moment */
- ro_gui_tree_icon.flags = wimp_ICON_INDIRECTED | wimp_ICON_VCENTRED;
- if (selected)
- ro_gui_tree_icon.flags |= wimp_ICON_SELECTED;
- ro_gui_tree_icon.extent.x0 = tree->offset_x + element->box.x;
- ro_gui_tree_icon.extent.y1 = -tree->offset_y - element->box.y -
- toolbar_height;
- ro_gui_tree_icon.extent.x1 = ro_gui_tree_icon.extent.x0 +
- NODE_INSTEP;
- ro_gui_tree_icon.extent.y0 = -tree->offset_y - element->box.y -
- element->box.height - toolbar_height;
- ro_gui_tree_icon.flags |= wimp_ICON_TEXT | wimp_ICON_SPRITE;
- ro_gui_tree_icon.data.indirected_text_and_sprite.text =
- ro_gui_tree_icon_null;
- ro_gui_tree_icon.data.indirected_text_and_sprite.validation =
- ro_gui_tree_icon_validation;
- ro_gui_tree_icon.data.indirected_text_and_sprite.size = 1;
- if (element->parent->expanded) {
- sprintf(ro_gui_tree_icon_validation, "S%s",
- element->sprite->expanded_name);
- } else {
- sprintf(ro_gui_tree_icon_validation, "S%s",
- element->sprite->name);
- }
- error = xwimp_plot_icon(&ro_gui_tree_icon);
- if (error) {
- LOG(("xwimp_plot_icon: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("WimpError", error->errmess);
- }
- x0 += NODE_INSTEP;
+ tv->drag = false;
- /* fall through */
- case NODE_ELEMENT_TEXT:
- assert(element->text);
+ /* Register wimp events to handle the supplied window. */
- if (element == tree->editing)
- return;
+ ro_gui_wimp_event_register_redraw_window(tv->w, ro_treeview_redraw);
+ ro_gui_wimp_event_register_open_window(tv->w, ro_treeview_open);
+ ro_gui_wimp_event_register_mouse_click(tv->w, ro_treeview_mouse_click);
+ ro_gui_wimp_event_register_keypress(tv->w, ro_treeview_keypress);
+ ro_gui_wimp_event_set_user_data(tv->w, tv);
- if (ro_gui_tree_icon.flags & wimp_ICON_SELECTED)
- ro_gui_tree_icon.flags |= wimp_ICON_FILLED;
- if (selected) {
- error = xcolourtrans_set_gcol((os_colour)0x00000000, 0,
- os_ACTION_OVERWRITE, 0, 0);
- if (error) {
- LOG(("xcolourtrans_set_gcol: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("MiscError", error->errmess);
- return;
- }
- error = xos_plot(os_MOVE_TO, x0, y0);
- if (!error)
- error = xos_plot(os_PLOT_RECTANGLE | os_PLOT_TO, x1-1, y1-1);
- if (error) {
- LOG(("xos_plot: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("MiscError", error->errmess);
- return;
- }
- bg = 0x0000000;
- c = 0x00eeeeee;
- } else {
- bg = 0x00ffffff;
- c = 0x00000000;
- }
- error = xcolourtrans_set_font_colours(font_CURRENT,
- bg << 8, c << 8, 14, 0, 0, 0);
- if (error) {
- LOG(("xcolourtrans_set_font_colours: 0x%x: %s",
- error->errnum, error->errmess));
- return;
- }
- code = rufl_paint(ro_gui_desktop_font_family, ro_gui_desktop_font_style,
- ro_gui_desktop_font_size,
- element->text, strlen(element->text),
- x0 + 8, y0 + 10,
- rufl_BLEND_FONT);
- if (code != rufl_OK) {
- if (code == rufl_FONT_MANAGER_ERROR)
- LOG(("rufl_paint: rufl_FONT_MANAGER_ERROR: 0x%x: %s",
- rufl_fm_error->errnum,
- rufl_fm_error->errmess));
- else
- LOG(("rufl_paint: 0x%x", code));
- }
- break;
- case NODE_ELEMENT_THUMBNAIL:
- url_element = tree_find_element(element->parent, TREE_ELEMENT_URL);
- if (url_element)
- bitmap = urldb_get_thumbnail(url_element->text);
- if (bitmap) {
- frame = bitmap_get_buffer((struct bitmap *) bitmap);
- if (!frame)
- urldb_set_thumbnail(url_element->text, NULL);
- if ((!frame) || (element->box.width == 0)) {
- update = calloc(sizeof(struct node_update), 1);
- if (!update)
- return;
- update->tree = tree;
- update->node = element->parent;
- schedule(0, tree_handle_node_changed_callback,
- update);
- return;
- }
- image_redraw(bitmap->sprite_area,
- ro_gui_tree_origin_x + element->box.x + 2,
- ro_gui_tree_origin_y - element->box.y,
- bitmap->width, bitmap->height,
- bitmap->width, bitmap->height,
- 0xffffff,
- false, false, false,
- IMAGE_PLOT_TINCT_OPAQUE);
- if (!tree->no_furniture) {
- tree_draw_line(element->box.x,
- element->box.y,
- element->box.width - 1,
- 0);
- tree_draw_line(element->box.x,
- element->box.y,
- 0,
- element->box.height - 3);
- tree_draw_line(element->box.x,
- element->box.y + element->box.height - 3,
- element->box.width - 1,
- 0);
- tree_draw_line(element->box.x + element->box.width - 1,
- element->box.y,
- 0,
- element->box.height - 3);
- }
- }
- break;
- }
-}
+ /* \todo Register wimp events to handle the supplied toolbar? */
-
-void tree_handle_node_changed_callback(void *p)
-{
- struct node_update *update = p;
-
- tree_handle_node_changed(update->tree, update->node, true, false);
- free(update);
+ return tv;
}
-
/**
- * Draws an elements expansion icon
+ * Delete a RISC OS GUI implementation of a treeview tree. The window is
+ * *not* destroyed -- this must be done by the caller.
*
- * \param tree the tree to draw the expansion for
- * \param element the element to draw the expansion for
+ * \param tv The RISC OS treeview to delete.
*/
-void tree_draw_node_expansion(struct tree *tree, struct node *node)
+
+void ro_treeview_destroy(ro_treeview *tv)
{
- unsigned int type;
+ ro_gui_wimp_event_finalise(tv->w);
- assert(tree);
- assert(node);
+ tree_delete(tv->tree);
- if ((node->child) || (node->data.next)) {
- if (node->expanded) {
- type = TREE_COLLAPSE;
- } else {
- type = TREE_EXPAND;
- }
- _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
- ro_gui_tree_sprites[type],
- ro_gui_tree_origin_x + node->box.x -
- (NODE_INSTEP / 2) - 8,
- ro_gui_tree_origin_y - node->box.y -
- (TREE_TEXT_HEIGHT / 2) - 8,
- tinct_BILINEAR_FILTER);
-
- }
+ free(tv);
}
-
/**
- * Sets the origin variables to the correct values for a specified tree
+ * Change the redraw origin of a treeview tree in RISC OS graphics units.
*
- * \param tree the tree to set the origin for
+ * \param *tv The ro_treeview object to update.
+ * \param x The X position, in terms of the RO window work area.
+ * \param y The Y position, in terms of the RO window work area.
+ *
+ * \todo -- this probably needs a rework.
*/
-void tree_initialise_redraw(struct tree *tree)
+
+void ro_treeview_set_origin(ro_treeview *tv, int x, int y)
{
- os_error *error;
- wimp_window_state state;
+ if (tv != NULL) {
+ tv->origin.x = x;
+ tv->origin.y = y;
- assert(tree->handle);
+ /* Assuming that we know how big the tree currently is, then
+ * adjust the window work area extent to match. If we don't,
+ * then presumably the tree isn't in an open window yet and
+ * a subsequent Open Window Event should pick it up.
+ */
- state.w = (wimp_w)tree->handle;
- error = xwimp_get_window_state(&state);
- if (error) {
- LOG(("xwimp_get_window_state: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("WimpError", error->errmess);
+ if (tv->size.x != 0 && tv->size.y != 0)
+ ro_treeview_set_window_extent(tv,
+ tv->origin.x + tv->size.x,
+ tv->origin.y + tv->size.y);
}
-
- ro_gui_tree_origin_x = state.visible.x0 - state.xscroll + tree->offset_x;
- ro_gui_tree_origin_y = state.visible.y1 - state.yscroll - tree->offset_y;
- if (tree->toolbar)
- ro_gui_tree_origin_y -= ro_gui_theme_toolbar_height(tree->toolbar);
}
-
/**
- * Recalculates the dimensions of a node element.
+ * Return details of the tree block associated with an ro_treeview object.
*
- * \param element the element to recalculate
+ * \param *tv The ro_treeview object of interest.
+ * \return A pointer to the associated tree block.
*/
-void tree_recalculate_node_element(struct node_element *element)
-{
- const struct bitmap *bitmap = NULL;
- struct node_element *url_element;
- rufl_code code;
- assert(element);
-
- switch (element->type) {
- case NODE_ELEMENT_TEXT_PLUS_SPRITE:
- assert(element->sprite);
- case NODE_ELEMENT_TEXT:
- assert(element->text);
- code = rufl_width(ro_gui_desktop_font_family, ro_gui_desktop_font_style,
- ro_gui_desktop_font_size,
- element->text, strlen(element->text),
- &element->box.width);
- if (code != rufl_OK) {
- if (code == rufl_FONT_MANAGER_ERROR)
- LOG(("rufl_width: rufl_FONT_MANAGER_ERROR: 0x%x: %s",
- rufl_fm_error->errnum,
- rufl_fm_error->errmess));
- else
- LOG(("rufl_width: 0x%x", code));
- }
- element->box.width += 16;
- element->box.height = TREE_TEXT_HEIGHT;
- if (element->type == NODE_ELEMENT_TEXT_PLUS_SPRITE)
- element->box.width += NODE_INSTEP;
- break;
- case NODE_ELEMENT_THUMBNAIL:
- url_element = tree_find_element(element->parent, TREE_ELEMENT_URL);
- if (url_element)
- bitmap = urldb_get_thumbnail(url_element->text);
- if (bitmap) {
-/* if ((bitmap->width == 0) && (bitmap->height == 0))
- frame = bitmap_get_buffer(bitmap);
- element->box.width = bitmap->width * 2 + 2;
- element->box.height = bitmap->height * 2 + 4;
-*/ element->box.width = THUMBNAIL_WIDTH * 2 + 2;
- element->box.height = THUMBNAIL_HEIGHT * 2 + 4;
- } else {
- element->box.width = 0;
- element->box.height = 0;
- }
- }
+struct tree *ro_treeview_get_tree(ro_treeview *tv)
+{
+ return (tv != NULL) ? (tv->tree) : (NULL);
}
-
/**
- * Sets a node element as having a specific sprite.
+ * Return details of the RISC OS window handle associated with an
+ * ro_treeview object.
*
- * \param node the node to update
- * \param sprite the sprite to use
- * \param selected the expanded sprite name to use
+ * \param *tv The ro_treeview object of interest.
+ * \return The associated RISC OS window handle.
*/
-void tree_set_node_sprite(struct node *node, const char *sprite,
- const char *expanded)
-{
- assert(node);
- assert(sprite);
- assert(expanded);
- node->data.sprite = calloc(sizeof(struct node_sprite), 1);
- if (!node->data.sprite) return;
- node->data.type = NODE_ELEMENT_TEXT_PLUS_SPRITE;
- node->data.sprite->area = (osspriteop_area *)1;
- sprintf(node->data.sprite->name, sprite);
- sprintf(node->data.sprite->expanded_name, expanded);
+wimp_w ro_treeview_get_window(ro_treeview *tv)
+{
+ return (tv != NULL) ? (tv->w) : (NULL);
}
-
/**
- * Sets a node element as having a folder sprite
+ * Return an indication of whether the supplied treeview object contains a
+ * selection.
*
- * \param node the node to update
+ * \param *tv The ro_treeview object of interest.
+ * \return true if there is a selection in the tree; else false.
*/
-void tree_set_node_sprite_folder(struct node *node)
-{
- assert(node->folder);
- tree_set_node_sprite(node, "small_dir", "small_diro");
+bool ro_treeview_has_selection(ro_treeview *tv)
+{
+ if (tv != NULL)
+ return tree_node_has_selection(tree_get_root(tv->tree));
+ else
+ return false;
}
-
/**
- * Updates the node details for a URL node.
- * The internal node dimensions are not updated.
+ * Callback to force a redraw of part of the treeview window.
*
- * \param node the node to update
- * \param url the URL
- * \param data the data the node is linked to, or NULL for unlinked data
+ * \param x Min X Coordinate of area to be redrawn.
+ * \param y Min Y Coordinate of area to be redrawn.
+ * \param width Width of area to be redrawn.
+ * \param height Height of area to be redrawn.
+ * \param pw The treeview object to be redrawn.
*/
-void tree_update_URL_node(struct node *node,
- const char *url, const struct url_data *data)
+
+void ro_treeview_redraw_request(int x, int y, int width, int height,
+ void *pw)
{
- struct node_element *element;
- char buffer[256];
+ if (pw != NULL) {
+ ro_treeview *tv = (ro_treeview *) pw;
+ os_error *error;
+ wimp_draw update;
+ osbool more;
- assert(node);
+ /* The scale can't be changed; it's always 1:1. */
- element = tree_find_element(node, TREE_ELEMENT_URL);
- if (!element)
- return;
- if (data) {
- /* node is linked, update */
- assert(!node->editable);
- if (!data->title)
- urldb_set_url_title(url, url);
+ plot = ro_plotters;
+ ro_plot_set_scale(1.0);
- if (!data->title)
- return;
+ update.w = tv->w;
+ update.box.x0 = (2 * x) + tv->origin.x;
+ update.box.y0 = (-2 * (y + height)) + tv->origin.y;
+ update.box.x1 = (2 * (x + width)) + tv->origin.x;
+ update.box.y1 = (-2 * y) + tv->origin.y;
- node->data.text = data->title;
- } else {
- /* node is not linked, find data */
- assert(node->editable);
- data = urldb_get_url_data(element->text);
- if (!data)
+ error = xwimp_update_window(&update, &more);
+ if (error) {
+ LOG(("xwimp_update_window: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
return;
+ }
+ ro_treeview_redraw_loop(&update, tv, more);
}
-
- if (element) {
- sprintf(buffer, "small_%.3x", ro_content_filetype_from_type(data->type));
- if (ro_gui_wimp_sprite_exists(buffer))
- tree_set_node_sprite(node, buffer, buffer);
- else
- tree_set_node_sprite(node, "small_xxx", "small_xxx");
- }
-
- element = tree_find_element(node, TREE_ELEMENT_LAST_VISIT);
- if (element) {
- snprintf(buffer, 256, messages_get("TreeLast"),
- (data->last_visit > 0) ?
- ctime((time_t *)&data->last_visit) :
- messages_get("TreeUnknown"));
- if (data->last_visit > 0)
- buffer[strlen(buffer) - 1] = '\0';
- free((void *)element->text);
- element->text = strdup(buffer);
- }
-
- element = tree_find_element(node, TREE_ELEMENT_VISITS);
- if (element) {
- snprintf(buffer, 256, messages_get("TreeVisits"),
- data->visits);
- free((void *)element->text);
- element->text = strdup(buffer);
- }
}
-
-
/**
- * Updates the tree owner following a tree resize
+ * Pass RISC OS redraw events on to the treeview widget.
*
- * \param tree the tree to update the owner of
+ * \param *redraw Pointer to Redraw Event block.
*/
-void tree_resized(struct tree *tree)
+
+void ro_treeview_redraw(wimp_draw *redraw)
{
- os_error *error;
- wimp_window_state state;
+ osbool more;
+ os_error *error;
+ ro_treeview *tv;
- assert(tree->handle);
+ tv = (ro_treeview *) ro_gui_wimp_event_get_user_data(redraw->w);
+ if (tv == NULL) {
+ LOG(("NULL treeview block for window: 0x%x",
+ (unsigned int) redraw->w));
+ /* Don't return, as not servicing redraw events isn't a good
+ * idea. The following code must handle (tv == NULL)
+ * gracefully while clearing the redraw queue.
+ */
+ }
+ /* The scale can't be changed; it's always 1:1. */
- state.w = (wimp_w)tree->handle;
- error = xwimp_get_window_state(&state);
+ plot = ro_plotters;
+ ro_plot_set_scale(1.0);
+
+ error = xwimp_redraw_window(redraw, &more);
if (error) {
- LOG(("xwimp_get_window_state: 0x%x: %s",
+ LOG(("xwimp_redraw_window: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
return;
}
- if (state.flags & wimp_WINDOW_OPEN)
- ro_gui_tree_open(PTR_WIMP_OPEN(&state));
+
+ ro_treeview_redraw_loop(redraw, tv, more);
}
-
/**
- * Redraws a tree window
+ * Redraw a treeview window, once the initial readraw block has been collected.
*
- * \param redraw the area to redraw
- * \param tree the tree to redraw
+ * /param *redraw Pointer to redraw block.
+ * /param *tv The treeview object being redrawn.
+ * /param more Flag to show if more actions are required.
*/
-void ro_gui_tree_redraw(wimp_draw *redraw)
+
+void ro_treeview_redraw_loop(wimp_draw *redraw, ro_treeview *tv, osbool more)
{
- struct tree *tree;
- osbool more;
- int clip_x0, clip_x1, clip_y0, clip_y1, origin_x, origin_y;
+ os_error *error;
- tree = (struct tree *)ro_gui_wimp_event_get_user_data(redraw->w);
+ while (more) {
+ ro_plot_origin_x = redraw->box.x0 - redraw->xscroll;
+ ro_plot_origin_y = redraw->box.y1 - redraw->yscroll;
- assert(tree);
+ if (tv != NULL && tv->tree != NULL) {
+ tree_draw(tv->tree, tv->origin.x/2, -(tv->origin.y/2),
+ (redraw->clip.x0
+ -(ro_plot_origin_x+tv->origin.x))/2,
+ ((ro_plot_origin_y+tv->origin.y)
+ -redraw->clip.y1)/2,
+ (redraw->clip.x1 - redraw->clip.x0)/2,
+ (redraw->clip.y1 - redraw->clip.y0)/2);
+ }
- more = wimp_redraw_window(redraw);
- while (more) {
- clip_x0 = redraw->clip.x0;
- clip_y0 = redraw->clip.y0;
- clip_x1 = redraw->clip.x1;
- clip_y1 = redraw->clip.y1;
- origin_x = redraw->box.x0 - redraw->xscroll;
- origin_y = redraw->box.y1 - redraw->yscroll;
- if (tree->toolbar)
- origin_y -= ro_gui_theme_toolbar_height(tree->toolbar);
- tree_draw(tree, clip_x0 - origin_x - tree->offset_x,
- origin_y - clip_y1 - tree->offset_y,
- clip_x1 - clip_x0, clip_y1 - clip_y0);
- more = wimp_get_rectangle(redraw);
+ error = xwimp_get_rectangle(redraw, &more);
+ if (error) {
+ LOG(("xwimp_redraw_window: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ return;
+ }
}
}
-
/**
- * Handles a mouse click for a tree
+ * Callback to notify us of a new overall tree size.
*
- * \param pointer the pointer state
- * \param tree the tree to handle a click for
- * \return whether the click was handled
+ * \param tree The tree being resized.
+ * \param width The new width of the window.
+ * \param height The new height of the window.
+ * \param *pw The treeview object to be resized.
*/
-bool ro_gui_tree_click(wimp_pointer *pointer, struct tree *tree)
+
+void ro_treeview_resized(struct tree *tree, int width, int height,
+ void *pw)
{
- bool furniture;
- struct node *node;
- struct node *last;
- struct node_element *element;
- int x, y;
- int alt_pressed = 0;
- wimp_window_state state;
- wimp_caret caret;
- wimp_drag drag;
- wimp_auto_scroll_info scroll;
- os_error *error;
- os_box box = { pointer->pos.x - 34, pointer->pos.y - 34,
- pointer->pos.x + 34, pointer->pos.y + 34 };
+ if (pw != NULL) {
+ ro_treeview *tv = (ro_treeview *) pw;
- assert(tree);
- assert(tree->root);
+ /* Store the width and height in terms of RISC OS work area. */
- /* gain the input focus when required */
- state.w = (wimp_w)tree->handle;
- error = xwimp_get_window_state(&state);
- if (error)
- LOG(("xwimp_get_window_state: 0x%x: %s",
- error->errnum, error->errmess));
- error = xwimp_get_caret_position(&caret);
- if (error)
- LOG(("xwimp_get_caret_position: 0x%x: %s",
- error->errnum, error->errmess));
- if (((pointer->buttons == (wimp_CLICK_SELECT << 8)) ||
- (pointer->buttons == (wimp_CLICK_ADJUST << 8))) &&
- (caret.w != state.w)) {
- error = xwimp_set_caret_position((wimp_w)tree->handle, -1, -100,
- -100, 32, -1);
- if (error)
- LOG(("xwimp_set_caret_position: 0x%x: %s",
- error->errnum, error->errmess));
- }
+ tv->size.x = width * 2;
+ tv->size.y = -(height * 2);
- if (!tree->root->child)
- return true;
+ /* Resize the window. */
- tree_initialise_redraw(tree);
- x = pointer->pos.x - ro_gui_tree_origin_x;
- y = ro_gui_tree_origin_y - pointer->pos.y;
- element = tree_get_node_element_at(tree->root->child, x, y, &furniture);
-
-
- /* stop editing for anything but a drag */
- if ((tree->editing) && (pointer->i != tree->edit_handle) &&
- (pointer->buttons != (wimp_CLICK_SELECT << 4)))
- ro_gui_tree_stop_edit(tree);
-
- /* handle a menu click */
- if (pointer->buttons == wimp_CLICK_MENU) {
- if ((!element) || (!tree->root->child) ||
- (tree_has_selection(tree->root->child)))
- return true;
-
- node = element->parent;
- tree->temp_selection = node;
- node->selected = true;
- tree_handle_node_element_changed(tree, &node->data);
- return true;
-
+ ro_treeview_set_window_extent(tv, tv->size.x, tv->size.y);
}
+}
- /* no item either means cancel selection on (select) click or a drag */
- if (!element) {
- if (tree->single_selection) {
- tree_set_node_selected(tree, tree->root->child, false);
- return true;
- }
- if ((pointer->buttons == (wimp_CLICK_SELECT << 4)) ||
- (pointer->buttons == (wimp_CLICK_SELECT << 8)))
- tree_set_node_selected(tree, tree->root->child, false);
- if ((pointer->buttons == (wimp_CLICK_SELECT << 4)) ||
- (pointer->buttons == (wimp_CLICK_ADJUST << 4))) {
+/**
+ * Callback to request that a section of the tree is scrolled into view.
+ *
+ * \param y The Y coordinate of top of the area in NS units.
+ * \param height The height of the area in NS units.
+ * \param *pw The treeview object affected.
+ */
- scroll.w = (wimp_w)tree->handle;
- scroll.pause_zone_sizes.y0 = 80;
- scroll.pause_zone_sizes.y1 = 80;
- if (tree->toolbar)
- scroll.pause_zone_sizes.y1 +=
- ro_gui_theme_toolbar_height(tree->toolbar);
- scroll.pause_duration = 0;
- scroll.state_change = (void *)0;
- error = xwimp_auto_scroll(wimp_AUTO_SCROLL_ENABLE_VERTICAL,
- &scroll, 0);
- if (error)
- LOG(("xwimp_auto_scroll: 0x%x: %s",
- error->errnum, error->errmess));
+void ro_treeview_scroll_visible(int y, int height, void *pw)
+{
+ if (pw != NULL) {
+ ro_treeview *tv = (ro_treeview *) pw;
+ os_error *error;
+ wimp_window_state state;
+ int visible_t, visible_b;
+ int request_t, request_b;
- gui_current_drag_type = GUI_DRAG_TREE_SELECT;
- ro_gui_tree_current_drag_tree = tree;
- ro_gui_tree_current_drag_buttons = pointer->buttons;
-
- drag.w = (wimp_w)tree->handle;
- drag.type = wimp_DRAG_USER_RUBBER;
- drag.initial.x0 = pointer->pos.x;
- drag.initial.x1 = pointer->pos.x;
- drag.initial.y0 = pointer->pos.y;
- drag.initial.y1 = pointer->pos.y;
- drag.bbox.x0 = state.visible.x0;
- drag.bbox.x1 = state.visible.x1;
- drag.bbox.y0 = -16384;//state.visible.y0;
- drag.bbox.y1 = 16384;//state.visible.y1 - tree->offset_y;
- error = xwimp_drag_box_with_flags(&drag,
- wimp_DRAG_BOX_KEEP_IN_LINE |
- wimp_DRAG_BOX_CLIP);
- if (error)
- LOG(("xwimp_drag_box_with_flags: 0x%x: %s",
- error->errnum, error->errmess));
-
+ state.w = tv->w;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ LOG(("xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ return;
}
- return true;
- }
- node = element->parent;
+ /* Work out top and bottom of both the currently visible and
+ * the required areas, in terms of the RO work area.
+ */
- /* click on furniture or double click on folder toggles node expansion */
- if (((furniture) && ((pointer->buttons == wimp_CLICK_SELECT << 8) ||
- (pointer->buttons == wimp_CLICK_ADJUST << 8) ||
- (pointer->buttons == wimp_CLICK_SELECT) ||
- (pointer->buttons == wimp_CLICK_ADJUST))) ||
- ((!furniture) && (node->child) &&
- ((pointer->buttons == wimp_CLICK_SELECT) ||
- (pointer->buttons == wimp_CLICK_ADJUST)))) {
- node->expanded = !node->expanded;
- if (!furniture)
- node->selected = false;
- tree_handle_node_changed(tree, node, false, true);
+ visible_t = state.yscroll;
+ visible_b = state.yscroll
+ - (state.visible.y1 - state.visible.y0);
- /* find the last child node if expanded */
- last = node;
- if ((last->child) && (last->expanded)) {
- last = last->child;
- while ((last->next) || ((last->child) && (last->expanded))) {
- if (last->next)
- last = last->next;
- else
- last = last->child;
- }
- }
- /* scroll to the bottom element then back to the top */
- element = &last->data;
- if (last->expanded)
- for (; element->next; element = element->next);
- ro_gui_tree_scroll_visible(tree, element);
- ro_gui_tree_scroll_visible(tree, &node->data);
- return true;
- }
+ request_t = -(2 * y);// - tv->origin.y;
+ request_b = -(2 * (y + height));// - tv->origin.y;
- /* no use for any other furniture click */
- if (furniture)
- return true;
+ /* If the area is outside the visible window, then scroll it
+ * in to view.
+ */
- /* single/double alt+click starts editing */
- if ((node->editable) && (!tree->editing) &&
- ((element->data == TREE_ELEMENT_URL) ||
- (element->data == TREE_ELEMENT_TITLE)) &&
- ((pointer->buttons == wimp_CLICK_SELECT) ||
- (pointer->buttons == (wimp_CLICK_SELECT << 8)))) {
- xosbyte1(osbyte_SCAN_KEYBOARD, 2 ^ 0x80, 0, &alt_pressed);
- if (alt_pressed == 0xff) {
- ro_gui_tree_start_edit(tree, element, pointer);
- return true;
- }
- }
+ if (request_t > visible_t || request_b < visible_b) {
+ if (request_t > visible_t) {
+ state.yscroll = request_t;
+ } else if (request_b < visible_b) {
+ state.yscroll = request_b + tv->origin.y
+ + (state.visible.y1 - state.visible.y0);
- /* double click starts launches the leaf */
- if ((pointer->buttons == wimp_CLICK_SELECT) ||
- (pointer->buttons == wimp_CLICK_ADJUST)) {
- if (!ro_gui_tree_launch_node(tree, node))
- return false;
- if (pointer->buttons == wimp_CLICK_ADJUST)
- ro_gui_dialog_close((wimp_w)tree->handle);
- return true;
- }
+ /* If the required area is bigger than the
+ * visible extent, then align to the top and
+ * let the bottom disappear out of view.
+ */
- /* single click (select) cancels current selection and selects item */
- if ((pointer->buttons == (wimp_CLICK_SELECT << 8)) ||
- ((pointer->buttons == (wimp_CLICK_ADJUST << 8)) &&
- (tree->single_selection))) {
- if (!node->selected) {
- tree_set_node_selected(tree, tree->root->child, false);
- node->selected = true;
- tree_handle_node_element_changed(tree, &node->data);
- }
- return true;
- }
+ if (state.yscroll < request_t)
+ state.yscroll = request_t;
+ }
- /* single click (adjust) toggles item selection */
- if (pointer->buttons == (wimp_CLICK_ADJUST << 8)) {
- node->selected = !node->selected;
- tree_handle_node_element_changed(tree, &node->data);
- return true;
- }
-
- /* drag starts a drag operation */
- if ((!tree->editing) && ((pointer->buttons == (wimp_CLICK_SELECT << 4)) ||
- (pointer->buttons == (wimp_CLICK_ADJUST << 4)))) {
- if (tree->no_drag)
- return true;
-
- if (!node->selected) {
- node->selected = true;
- tree_handle_node_element_changed(tree, &node->data);
- }
-
- scroll.w = (wimp_w)tree->handle;
- scroll.pause_zone_sizes.y0 = 80;
- scroll.pause_zone_sizes.y1 = 80;
- if (tree->toolbar)
- scroll.pause_zone_sizes.y1 +=
- ro_gui_theme_toolbar_height(tree->toolbar);
- scroll.pause_duration = -1;
- scroll.state_change = (void *)0;
- error = xwimp_auto_scroll(wimp_AUTO_SCROLL_ENABLE_VERTICAL,
- &scroll, 0);
- if (error)
- LOG(("xwimp_auto_scroll: 0x%x: %s",
- error->errnum, error->errmess));
-
- gui_current_drag_type = GUI_DRAG_TREE_MOVE;
- ro_gui_tree_current_drag_tree = tree;
- ro_gui_tree_current_drag_buttons = pointer->buttons;
-
- node = tree_get_selected_node(tree->root);
- if (node) {
- if (node->folder) {
- if ((node->expanded) &&
- (ro_gui_wimp_sprite_exists("directoryo")))
- sprintf(ro_gui_tree_drag_name, "directoryo");
- else
- sprintf(ro_gui_tree_drag_name, "directory");
- } else {
- /* small_xxx -> file_xxx */
- sprintf(ro_gui_tree_drag_name, "file_%s",
- node->data.sprite->name + 6);
- if (!ro_gui_wimp_sprite_exists(ro_gui_tree_drag_name))
- sprintf(ro_gui_tree_drag_name, "file_xxx");
+ error = xwimp_open_window((wimp_open *) &state);
+ if (error) {
+ LOG(("xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ return;
}
- } else {
- sprintf(ro_gui_tree_drag_name, "package");
}
-
- error = xdragasprite_start(dragasprite_HPOS_CENTRE |
- dragasprite_VPOS_CENTRE |
- dragasprite_BOUND_POINTER |
- dragasprite_DROP_SHADOW,
- (osspriteop_area *) 1,
- ro_gui_tree_drag_name, &box, 0);
- if (error)
- LOG(("xdragasprite_start: 0x%x: %s",
- error->errnum, error->errmess));
- return true;
}
-
-
- return false;
}
-
/**
- * Handles a menu closed event
+ * Callback to return the tree window dimensions to the treeview system.
*
- * \param tree the tree to handle the event for
+ * \param *width Return the window width.
+ * \param *height Return the window height.
+ * \param *pw The treeview object to use.
*/
-void ro_gui_tree_menu_closed(struct tree *tree)
-{
- assert(tree);
- if (tree->temp_selection) {
- tree->temp_selection->selected = false;
- tree_handle_node_element_changed(tree, &tree->temp_selection->data);
- tree->temp_selection = NULL;
- ro_gui_menu_prepare_action((wimp_w)tree->handle, TREE_SELECTION, false);
- ro_gui_menu_prepare_action((wimp_w)tree->handle, TREE_EXPAND_ALL, false);
- }
-}
-
-
-/**
- * Respond to a mouse click for a tree (hotlist or history) toolbar
- *
- * \param pointer the pointer state
- */
-bool ro_gui_tree_toolbar_click(wimp_pointer* pointer)
+void ro_treeview_get_window_dimensions(int *width, int *height,
+ void *pw)
{
- struct node *node;
+ if (pw != NULL && (width != NULL || height != NULL)) {
+ ro_treeview *tv = (ro_treeview *) pw;
+ os_error *error;
+ wimp_window_state state;
- struct toolbar *toolbar =
- (struct toolbar *)ro_gui_wimp_event_get_user_data(pointer->w);
- assert(toolbar);
- struct tree *tree =
- (struct tree *)ro_gui_wimp_event_get_user_data(toolbar->parent_handle);
- assert(tree);
+ state.w = tv->w;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ LOG(("xwimp_get_window_info_header_only: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ return;
+ }
- ro_gui_tree_stop_edit(tree);
+ if (width != NULL)
+ *width = (state.visible.x1 - state.visible.x0) / 2;
- if (pointer->buttons == wimp_CLICK_MENU) {
- ro_gui_menu_create(tree_toolbar_menu, pointer->pos.x,
- pointer->pos.y, (wimp_w)tree->handle);
- return true;
+ if (height != NULL)
+ *height = (state.visible.y1 - state.visible.y0) / 2;
}
-
- if (tree->toolbar->editor) {
- ro_gui_theme_toolbar_editor_click(tree->toolbar, pointer);
- return true;
- }
-
- switch (pointer->i) {
- case ICON_TOOLBAR_CREATE:
- node = tree_create_folder_node(tree->root,
- messages_get("TreeNewFolder"));
- tree_redraw_area(tree, node->box.x - NODE_INSTEP,
- 0, NODE_INSTEP, 16384);
- tree_handle_node_changed(tree, node, false, true);
- ro_gui_tree_start_edit(tree, &node->data, NULL);
- break;
- case ICON_TOOLBAR_OPEN:
- tree_handle_expansion(tree, tree->root,
- (pointer->buttons == wimp_CLICK_SELECT),
- true, false);
- break;
- case ICON_TOOLBAR_EXPAND:
- tree_handle_expansion(tree, tree->root,
- (pointer->buttons == wimp_CLICK_SELECT),
- false, true);
- break;
- case ICON_TOOLBAR_DELETE:
- ro_gui_menu_handle_action((wimp_w)tree->handle,
- TREE_SELECTION_DELETE, false);
- break;
- case ICON_TOOLBAR_LAUNCH:
- ro_gui_menu_handle_action((wimp_w)tree->handle,
- TREE_SELECTION_LAUNCH, false);
- break;
- }
- return true;
}
-
/**
- * Starts an editing session
+ * Resize the RISC OS window extent of a treeview.
*
- * \param tree the tree to start editing for
- * \param element the element to edit
- * \param pointer the pointer data to use for caret positioning (or NULL)
+ * \param *tv The RISC OS treeview object to resize.
+ * \param width The new width of the work area, in RO units.
+ * \param height The new height of the work area, in RO units.
*/
-void ro_gui_tree_start_edit(struct tree *tree, struct node_element *element,
- wimp_pointer *pointer)
+
+void ro_treeview_set_window_extent(ro_treeview *tv, int width, int height)
{
- os_error *error;
- struct node *parent;
- int toolbar_height = 0;
+ if (tv != NULL) {
+ os_error *error;
+ os_box extent;
+ wimp_window_state state;
+ int new_x, new_y;
+ int visible_x, visible_y;
+ int new_x_scroll, new_y_scroll;
- assert(tree);
- assert(element);
+ /* Calculate the new window extents, in RISC OS units. */
- if (tree->editing)
- ro_gui_tree_stop_edit(tree);
- if (tree->toolbar)
- toolbar_height = ro_gui_theme_toolbar_height(tree->toolbar);
+ new_x = width + tv->origin.x;
+ new_y = height + tv->origin.y;
- parent = element->parent;
- if (&parent->data == element)
- parent = parent->parent;
- for (; parent; parent = parent->parent) {
- if (!parent->expanded) {
- parent->expanded = true;
- tree_handle_node_changed(tree, parent, false, true);
+ /* Get details of the existing window, and start to sanity
+ * check the new extents.
+ */
+
+ state.w = tv->w;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ LOG(("xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ return;
}
- }
- tree->editing = element;
- ro_gui_tree_edit_icon.w = (wimp_w)tree->handle;
- ro_gui_tree_edit_icon.icon.extent.x0 = tree->offset_x + element->box.x - 2;
- ro_gui_tree_edit_icon.icon.extent.x1 = tree->offset_x +
- element->box.x + element->box.width + 2;
- ro_gui_tree_edit_icon.icon.extent.y1 = -tree->offset_y - toolbar_height -
- element->box.y;
- ro_gui_tree_edit_icon.icon.extent.y0 = -tree->offset_y - toolbar_height -
- element->box.y - element->box.height;
- if (element->type == NODE_ELEMENT_TEXT_PLUS_SPRITE)
- ro_gui_tree_edit_icon.icon.extent.x0 += NODE_INSTEP;
- ro_gui_tree_edit_icon.icon.data.indirected_text.text =
- (char *) element->text;
- error = xwimp_create_icon(&ro_gui_tree_edit_icon,
- (wimp_i *)&tree->edit_handle);
- if (error)
- LOG(("xwimp_create_icon: 0x%x: %s",
- error->errnum, error->errmess));
+ /* If the extent is smaller than the current visible area,
+ * then extend it so that it matches the visible area.
+ */
- tree->textarea_handle = ro_textarea_create((wimp_w)tree->handle,
- (wimp_i)tree->edit_handle, 0, ro_gui_desktop_font_family,
- ro_gui_desktop_font_size,
- ro_gui_desktop_font_style);
- if (!tree->textarea_handle) {
- ro_gui_tree_stop_edit(tree);
- return;
- }
- ro_textarea_set_text(tree->textarea_handle, element->text);
- if (pointer)
- ro_textarea_set_caret_xy(tree->textarea_handle,
- pointer->pos.x, pointer->pos.y);
- else
- ro_textarea_set_caret(tree->textarea_handle,
- strlen(element->text));
+ if (new_x < (state.visible.x1 - state.visible.x0))
+ new_x = state.visible.x1 - state.visible.x0;
- tree_handle_node_element_changed(tree, element);
- ro_gui_tree_scroll_visible(tree, element);
-}
+ if (new_y > (state.visible.y0 - state.visible.y1))
+ new_y = state.visible.y0 - state.visible.y1;
+ /* Calculate the maximum visible coordinates of the existing
+ * window.
+ */
-/**
- * Stops any current editing session
- *
- * \param tree the tree to stop editing for
- */
-void ro_gui_tree_stop_edit(struct tree *tree)
-{
- os_error *error;
+ visible_x = state.xscroll +
+ (state.visible.x1 - state.visible.x0);
+ visible_y = state.yscroll +
+ (state.visible.y0 - state.visible.y1);
- assert(tree);
+ /* If the window is currently open, and the exising visible
+ * area is bigger than the new extent, then we need to reopen
+ * the window in an appropriare position before setting the
+ * new extent.
+ */
- if (!tree->editing) return;
+ if ((state.flags & wimp_WINDOW_OPEN) &&
+ (visible_x > new_x || visible_y < new_y)) {
+ new_x_scroll = state.xscroll;
+ new_y_scroll = state.yscroll;
- if (tree->textarea_handle) {
- ro_textarea_destroy(tree->textarea_handle);
- tree->textarea_handle = 0;
- }
- error = xwimp_delete_icon((wimp_w)tree->handle, (wimp_i)tree->edit_handle);
- if (error)
- LOG(("xwimp_delete_icon: 0x%x: %s",
- error->errnum, error->errmess));
- tree_handle_node_element_changed(tree, tree->editing);
- tree->editing = NULL;
+ if (visible_x > new_x)
+ new_x_scroll = new_x - (state.visible.x1
+ - state.visible.x0);
- error = xwimp_set_caret_position((wimp_w)tree->handle, -1, -100,
- -100, 32, -1);
- if (error)
- LOG(("xwimp_set_caret_position: 0x%x: %s",
- error->errnum, error->errmess));
- tree_recalculate_size(tree);
-}
+ if (visible_y < new_y)
+ new_y_scroll = new_y - (state.visible.y0
+ - state.visible.y1);
+ if (new_x_scroll < 0) {
+ state.visible.x1 -= new_x_scroll;
+ state.xscroll = 0;
+ } else {
+ state.xscroll = new_x_scroll;
+ }
-/**
- * Scrolls the tree to make an element visible
- *
- * \param tree the tree to scroll
- * \param element the element to display
- */
-void ro_gui_tree_scroll_visible(struct tree *tree, struct node_element *element)
-{
- wimp_window_state state;
- int x0, x1, y0, y1;
- os_error *error;
- int toolbar_height = 0;
+ if (new_y_scroll > 0) {
+ state.visible.y0 += new_y_scroll;
+ state.yscroll = 0;
+ } else {
+ state.yscroll = new_y_scroll;
+ }
- assert(element);
+ error = xwimp_open_window((wimp_open *) &state);
+ if (error) {
+ LOG(("xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ return;
+ }
- if (tree->toolbar)
- toolbar_height = ro_gui_theme_toolbar_height(tree->toolbar);
+ /* \todo -- Not sure if we need to reattach the
+ * toolbar here: the nested wimp seems to take care
+ * of it for us?
+ */
+ }
- state.w = (wimp_w)tree->handle;
- error = xwimp_get_window_state(&state);
- if (error)
- LOG(("xwimp_get_window_state: 0x%x: %s",
- error->errnum, error->errmess));
- if (!(state.flags & wimp_WINDOW_OPEN))
- return;
- x0 = state.xscroll;
- y0 = -state.yscroll;
- x1 = x0 + state.visible.x1 - state.visible.x0 - tree->offset_x;
- y1 = y0 - state.visible.y0 + state.visible.y1 - tree->offset_y - toolbar_height;
+ /* Now that the new extent fits into the visible window, we
+ * can resize the work area. If we succeed, the values are
+ * recorded to save having to ask the Wimp for them
+ * each time.
+ */
- state.yscroll = state.visible.y1 - state.visible.y0 - tree->offset_y -
- toolbar_height - y1;
- if ((element->box.y >= y0) && (element->box.y + element->box.height <= y1))
- return;
- if (element->box.y < y0)
- state.yscroll = -element->box.y;
- if (element->box.y + element->box.height > y1)
- state.yscroll = state.visible.y1 - state.visible.y0 -
- tree->offset_y - toolbar_height -
- (element->box.y + element->box.height);
- ro_gui_tree_open(PTR_WIMP_OPEN(&state));
-}
+ extent.x0 = 0;
+ extent.y0 = new_y;
+ extent.x1 = new_x;
+ extent.y1 = 0;
-
-/**
- * Shows the a tree window.
- */
-void ro_gui_tree_show(struct tree *tree)
-{
- struct toolbar *toolbar;
-
- /* we may have failed to initialise */
- if (!tree) return;
- toolbar = tree->toolbar;
-
- /* handle first time opening */
- if (!ro_gui_dialog_open_top((wimp_w)tree->handle, toolbar, 600, 800)) {
- ro_gui_tree_stop_edit(tree);
- if (tree->root->child) {
- tree_set_node_selected(tree, tree->root, false);
- tree_handle_node_changed(tree, tree->root,
- false, true);
+ error = xwimp_set_extent(tv->w, &extent);
+ if (error) {
+ LOG(("xwimp_set_extent: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ return;
}
- }
- /* set the caret position */
- xwimp_set_caret_position((wimp_w)tree->handle, -1, -100, -100, 32, -1);
+ tv->extent.x = new_x;
+ tv->extent.y = new_y;
+ }
}
-
/**
- * Handles a window open request
+ * Handle RISC OS Window Open events for a treeview window.
*
- * \param open the window state
+ * \param *open Pointer to the Window Open Event block.
*/
-void ro_gui_tree_open(wimp_open *open)
+
+static void ro_treeview_open(wimp_open *open)
{
- struct tree *tree;
- os_error *error;
- int width;
- int height;
- int toolbar_height = 0;
- bool vscroll;
+ ro_treeview *tv;
+ os_error *error;
+ os_box extent;
+ int width, height;
- tree = (struct tree *)ro_gui_wimp_event_get_user_data(open->w);
-
- if (!tree)
+ tv = (ro_treeview *) ro_gui_wimp_event_get_user_data(open->w);
+ if (tv == NULL) {
+ LOG(("NULL treeview block for window: ox%x",
+ (unsigned int) open->w));
return;
- if (tree->toolbar)
- toolbar_height = ro_gui_theme_toolbar_height(tree->toolbar);
+ }
+ /* Calculate the window work area. It must be at least the same as
+ * the current visible area of the window, and needs to contain the
+ * tree as defined by size.x + offset.x and size.y + offset.y (note
+ * that the offset.y should be set to cover any toolbar, so we can
+ * ignore the size of that).
+ */
+
width = open->visible.x1 - open->visible.x0;
- if (width < (tree->offset_x + tree->width))
- width = tree->offset_x + tree->width;
- height = open->visible.y1 - open->visible.y0;
- if (height < (tree->offset_y + toolbar_height + tree->height))
- height = tree->offset_y + toolbar_height + tree->height;
+ height = open->visible.y0 - open->visible.y1;
- if ((height != tree->window_height) || (width != tree->window_width)) {
- os_box extent = { 0, -height, width, 0};
- error = xwimp_set_extent((wimp_w)tree->handle, &extent);
+ if (tv->size.x != 0 && width < (tv->origin.x + tv->size.x))
+ width = (tv->origin.x + tv->size.x);
+
+ if (tv->size.y != 0 && height > (tv->size.y + tv->origin.y))
+ height = (tv->size.y + tv->origin.y);
+
+ if (width != tv->extent.x || height != tv->extent.y) {
+ extent.x0 = 0;
+ extent.y0 = height;
+ extent.x1 = width;
+ extent.y1 = 0;
+
+ error = xwimp_set_extent(tv->w, &extent);
if (error) {
LOG(("xwimp_set_extent: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
+ return;
}
- /* hide the scroll bar? */
- if ((tree->no_vscroll) && (height != tree->window_height)) {
- vscroll = (tree->height > height);
- if (ro_gui_wimp_check_window_furniture(open->w,
- wimp_WINDOW_VSCROLL) != vscroll) {
- ro_gui_wimp_update_window_furniture(open->w,
- 0, wimp_WINDOW_VSCROLL);
- if (vscroll)
- open->visible.x1 -= ro_get_vscroll_width(open->w);
- else
- open->visible.x1 += ro_get_vscroll_width(open->w);
- }
- }
-
- tree->window_width = width;
- tree->window_height = height;
+ tv->extent.x = width;
+ tv->extent.y = height;
}
+ /* \todo -- Might need to add vertical scrollbar hiding back in here? */
+
error = xwimp_open_window(open);
if (error) {
LOG(("xwimp_open_window: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
}
- if (tree->toolbar)
- ro_gui_theme_process_toolbar(tree->toolbar, -1);
- ro_gui_menu_prepare_action((wimp_w)tree->handle, TREE_SELECTION, false);
- ro_gui_menu_prepare_action((wimp_w)tree->handle, TREE_EXPAND_ALL, false);
+
+ if (tv->tb)
+ ro_gui_theme_process_toolbar(tv->tb, -1);
}
/**
- * Handles a keypress for a tree
+ * Pass RISC OS Mouse Click events on to the treeview widget.
*
- * \param key the key pressed
- * \param tree the tree to handle a keypress for
- * \return whether the key was processed
+ * \param *pointer Pointer to the Mouse Click Event block.
+ * \return Return true if click handled; else false.
*/
-bool ro_gui_tree_keypress(wimp_key *key)
+
+static bool ro_treeview_mouse_click(wimp_pointer *pointer)
{
- wimp_window_state state;
- int y;
- char *new_string;
- struct tree *tree;
- int strlen;
- os_error *error;
+ os_error *error;
+ ro_treeview *tv;
+ wimp_window_state state;
+ int xpos, ypos;
+ browser_mouse_state mouse;
- tree = (struct tree *)ro_gui_wimp_event_get_user_data(key->w);
- if (!tree)
+ tv = (ro_treeview *) ro_gui_wimp_event_get_user_data(pointer->w);
+ if (tv == NULL) {
+ LOG(("NULL treeview block for window: 0x%x",
+ (unsigned int) pointer->w));
return false;
-
- /* Handle basic keys
- */
- switch (key->c) {
- case 1: /* CTRL+A */
- ro_gui_menu_handle_action((wimp_w)tree->handle,
- TREE_SELECT_ALL, false);
- return true;
- case 24: /* CTRL+X */
- ro_gui_menu_handle_action((wimp_w)tree->handle,
- TREE_SELECTION_DELETE, false);
- return true;
- case 26: /* CTRL+Z */
- ro_gui_menu_handle_action((wimp_w)tree->handle,
- TREE_CLEAR_SELECTION, false);
- return true;
- case wimp_KEY_RETURN:
- if ((tree->editing) && (tree->textarea_handle)) {
- strlen = ro_textarea_get_text(
- tree->textarea_handle,
- NULL, 0);
- if (strlen == -1) {
- ro_gui_tree_stop_edit(tree);
- return true;
- }
- new_string = malloc(strlen);
- if (!new_string) {
- ro_gui_tree_stop_edit(tree);
- LOG(("No memory for malloc()"));
- warn_user("NoMemory", 0);
- return true;
- }
- ro_textarea_get_text(tree->textarea_handle,
- new_string, strlen);
- free((void *)tree->editing->text);
- tree->editing->text = new_string;
- ro_gui_tree_stop_edit(tree);
- tree_recalculate_size(tree);
- } else {
- ro_gui_tree_launch_selected(tree);
- }
- return true;
- case wimp_KEY_ESCAPE:
- if (tree->editing) {
- ro_gui_tree_stop_edit(tree);
- } else {
- /* \todo cancel drags etc. */
- }
- return true;
-
- case IS_WIMP_KEY | wimp_KEY_UP:
- case IS_WIMP_KEY | wimp_KEY_DOWN:
- case IS_WIMP_KEY | wimp_KEY_PAGE_UP:
- case IS_WIMP_KEY | wimp_KEY_PAGE_DOWN:
- case IS_WIMP_KEY | wimp_KEY_HOME:
- case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_UP:
- case IS_WIMP_KEY | wimp_KEY_END:
- case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_DOWN:
- break;
- default:
- return false;
}
- /* keyboard scrolling */
- state.w = (wimp_w)tree->handle;
+ state.w = tv->w;
error = xwimp_get_window_state(&state);
if (error) {
LOG(("xwimp_get_window_state: 0x%x: %s",
error->errnum, error->errmess));
- return true;
+ warn_user("WimpError", error->errmess);
+ return false;
}
- y = state.visible.y1 - state.visible.y0 - TREE_TEXT_HEIGHT;
- if (tree->toolbar)
- y -= ro_gui_theme_toolbar_full_height(tree->toolbar);
+ /* Convert the returned mouse coordinates into NetSurf's internal
+ * units.
+ */
- switch (key->c) {
- case IS_WIMP_KEY | wimp_KEY_UP:
-/* if ((state.yscroll % TREE_TEXT_HEIGHT) != 0)
- state.yscroll -= (state.yscroll % TREE_TEXT_HEIGHT);
- else
-*/ state.yscroll += TREE_TEXT_HEIGHT;
- break;
- case IS_WIMP_KEY | wimp_KEY_DOWN:
-/* if (((state.yscroll + y) % TREE_TEXT_HEIGHT) != 0)
- state.yscroll -= ((state.yscroll + y) % TREE_TEXT_HEIGHT);
- else
-*/ state.yscroll -= TREE_TEXT_HEIGHT;
- break;
- case IS_WIMP_KEY | wimp_KEY_PAGE_UP:
- state.yscroll += y;
- break;
- case IS_WIMP_KEY | wimp_KEY_PAGE_DOWN:
- state.yscroll -= y;
- break;
- case IS_WIMP_KEY | wimp_KEY_HOME:
- case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_UP:
- state.yscroll = 0x10000000;
- break;
- case IS_WIMP_KEY | wimp_KEY_END:
- case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_DOWN:
- state.yscroll = -0x10000000;
- break;
- }
+ xpos = ((pointer->pos.x - state.visible.x0) +
+ state.xscroll - tv->origin.x) / 2;
+ ypos = ((state.visible.y1 - pointer->pos.y) -
+ state.yscroll + tv->origin.y) / 2;
- error = xwimp_open_window(PTR_WIMP_OPEN(&state));
- if (error) {
- LOG(("xwimp_open_window: 0x%x: %s",
- error->errnum, error->errmess));
+ /* Start to process the mouse click.
+ *
+ * Select and Adjust are processed normally. To get filer-like operation
+ * with selections, Menu clicks are passed to the treeview first as
+ * Select if there are no selected nodes in the tree.
+ */
+
+ mouse = 0;
+
+ if (pointer->buttons == wimp_CLICK_MENU) {
+ if (!tree_node_has_selection(tree_get_root(tv->tree)))
+ mouse |= BROWSER_MOUSE_CLICK_1;
+ } else {
+ mouse = ro_gui_mouse_click_state(pointer->buttons,
+ wimp_BUTTON_DOUBLE_CLICK_DRAG);
+
+ /* Record drag start */
+ if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) {
+ tv->drag_start.x = xpos;
+ tv->drag_start.y = ypos;
+ tv->drag = true;
+ }
+
+ if (mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_MOD_2))
+ xwimp_set_caret_position(tv->w, -1, -100, -100, 32, -1);
}
+ if (mouse != 0)
+ tree_mouse_action(tv->tree, mouse, xpos, ypos);
+
+ /* We assume that the owning module will have attached a window menu
+ * to our parent window. If it hasn't, this call will quietly fail.
+ */
+
+ if (pointer->buttons == wimp_CLICK_MENU)
+ ro_gui_wimp_event_process_window_menu_click(pointer);
+
return true;
}
-
/**
- * Handles the completion of a selection drag (GUI_DRAG_TREE_SELECT)
+ * Track the mouse under Null Polls from the wimp, to support dragging.
*
- * \param drag the drag box information
+ * \param w Window handle currently under the mouse.
+ * \param *pointer Pointer to a Wimp Pointer block.
*/
-void ro_gui_tree_selection_drag_end(wimp_dragged *drag)
+
+void ro_treeview_mouse_at(wimp_w w, wimp_pointer *pointer)
{
- wimp_window_state state;
- wimp_auto_scroll_info scroll;
- os_error *error;
- int x0, y0, x1, y1;
- int toolbar_height = 0;
+ os_error *error;
+ ro_treeview *tv;
+ wimp_window_state state;
+ int xpos, ypos;
+ browser_mouse_state mouse;
- if (ro_gui_tree_current_drag_tree->toolbar)
- toolbar_height = ro_gui_theme_toolbar_height(
- ro_gui_tree_current_drag_tree->toolbar);
+ tv = (ro_treeview *) ro_gui_wimp_event_get_user_data(pointer->w);
+ if (tv == NULL) {
+ LOG(("NULL treeview block for window: 0x%x",
+ (unsigned int) pointer->w));
+ return;
+ }
- scroll.w = (wimp_w)ro_gui_tree_current_drag_tree->handle;
- error = xwimp_auto_scroll(0, &scroll, 0);
- if (error)
- LOG(("xwimp_auto_scroll: 0x%x: %s", error->errnum, error->errmess));
-
- state.w = (wimp_w)ro_gui_tree_current_drag_tree->handle;
+ state.w = tv->w;
error = xwimp_get_window_state(&state);
if (error) {
LOG(("xwimp_get_window_state: 0x%x: %s",
@@ -1437,177 +809,177 @@
return;
}
- x0 = drag->final.x0 - state.visible.x0 - state.xscroll +
- ro_gui_tree_current_drag_tree->offset_x;
- y0 = state.visible.y1 - state.yscroll - drag->final.y0 -
- ro_gui_tree_current_drag_tree->offset_y - toolbar_height;
- x1 = drag->final.x1 - state.visible.x0 - state.xscroll +
- ro_gui_tree_current_drag_tree->offset_x;
- y1 = state.visible.y1 - state.yscroll - drag->final.y1 -
- ro_gui_tree_current_drag_tree->offset_y - toolbar_height;
- tree_handle_selection_area(ro_gui_tree_current_drag_tree, x0, y0,
- x1 - x0, y1 - y0,
- (ro_gui_tree_current_drag_buttons == (wimp_CLICK_ADJUST << 4)));
- ro_gui_menu_prepare_action((wimp_w)ro_gui_tree_current_drag_tree->handle,
- TREE_SELECTION, false);
- ro_gui_menu_prepare_action((wimp_w)ro_gui_tree_current_drag_tree->handle,
- TREE_EXPAND_ALL, false);
-}
+ /* Convert the returned mouse coordinates into NetSurf's internal
+ * units.
+ */
+ xpos = ((pointer->pos.x - state.visible.x0) +
+ state.xscroll - tv->origin.x) / 2;
+ ypos = ((state.visible.y1 - pointer->pos.y) -
+ state.yscroll + tv->origin.y) / 2;
-/**
- * Converts screen co-ordinates to tree ones
- *
- * \param tree the tree to calculate for
- * \param x the screen x co-ordinate
- * \param x the screen y co-ordinate
- * \param tree_x updated to the tree x co-ordinate
- * \param tree_y updated to the tree y co-ordinate
- */
-void ro_gui_tree_get_tree_coordinates(struct tree *tree, int x, int y,
- int *tree_x, int *tree_y) {
- wimp_window_state state;
- os_error *error;
+ /* Start to process the mouse click. */
- state.w = (wimp_w)tree->handle;
- error = xwimp_get_window_state(&state);
- if (error) {
- LOG(("xwimp_get_window_state: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("WimpError", error->errmess);
- return;
+ mouse = 0;
+
+ if (!(pointer->buttons & (wimp_CLICK_MENU))) {
+ mouse = ro_gui_mouse_drag_state(pointer->buttons,
+ wimp_BUTTON_DOUBLE_CLICK_DRAG);
+ if (mouse != 0)
+ tree_mouse_action(tv->tree, mouse, xpos, ypos);
+
+ /* Check if drag ended and tell core */
+ if (tv->drag && !(mouse & BROWSER_MOUSE_DRAG_ON)) {
+ tree_drag_end(tv->tree, mouse, tv->drag_start.x,
+ tv->drag_start.y, xpos, ypos);
+ tv->drag = false;
+ }
+
}
- *tree_x = x - state.visible.x0 - state.xscroll + tree->offset_x;
- *tree_y = state.visible.y1 - state.yscroll - y - tree->offset_y;
- if (tree->toolbar)
- *tree_y -= ro_gui_theme_toolbar_height(tree->toolbar);
}
-
/**
- * Handles the completion of a move drag (GUI_DRAG_TREE_MOVE)
+ * Pass RISC OS keypress events on to the treeview widget.
*
- * \param drag the drag box information
+ * \param *key Pointer to the Key Pressed Event block.
+ * \return Return true if keypress handled; else false.
*/
-void ro_gui_tree_move_drag_end(wimp_dragged *drag)
+
+static bool ro_treeview_keypress(wimp_key *key)
{
- struct gui_window *g;
- wimp_pointer pointer;
- wimp_auto_scroll_info scroll;
- os_error *error;
- struct node *node;
- struct node *single;
- struct node_element *element;
- bool before;
- int x, y;
+ ro_treeview *tv;
+ uint32_t c;
- scroll.w = (wimp_w)ro_gui_tree_current_drag_tree->handle;
- error = xwimp_auto_scroll(0, &scroll, 0);
- if (error)
- LOG(("xwimp_auto_scroll: 0x%x: %s", error->errnum, error->errmess));
-
- error = xwimp_get_pointer_info(&pointer);
- if (error) {
- LOG(("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess));
- warn_user("WimpError", error->errmess);
- return;
+ tv = (ro_treeview *) ro_gui_wimp_event_get_user_data(key->w);
+ if (tv == NULL) {
+ LOG(("NULL treeview block for window: 0x%x",
+ (unsigned int) key->w));
+ return false;
}
- if (pointer.w != (wimp_w)ro_gui_tree_current_drag_tree->handle) {
- /* try to drop into a browser window */
- single = tree_get_selected_node(ro_gui_tree_current_drag_tree->root->child);
- element = tree_find_element(single, TREE_ELEMENT_URL);
- if (!element)
- return;
- if (single) {
- /* \todo:send datasave for element */
- g = ro_gui_window_lookup(pointer.w);
- if (g)
- browser_window_go(g->bw, element->text, 0, true);
- return;
- } else {
- /* \todo:update save.c to handle multiple concurrent saves */
+ c = (uint32_t) key->c;
+
+ if ((unsigned)c < 0x20 || (0x7f <= c && c <= 0x9f) ||
+ (c & IS_WIMP_KEY)) {
+ /* Munge control keys into unused control chars */
+ /* We can't map onto 1->26 (reserved for ctrl+<qwerty>
+ That leaves 27->31 and 128->159 */
+ switch (c & ~IS_WIMP_KEY) {
+ case wimp_KEY_TAB: c = 9; break;
+ case wimp_KEY_SHIFT | wimp_KEY_TAB: c = 11; break;
+
+ /* cursor movement keys */
+ case wimp_KEY_HOME:
+ case wimp_KEY_CONTROL | wimp_KEY_LEFT:
+ c = KEY_LINE_START;
+ break;
+ case wimp_KEY_END:
+ if (os_version >= RISCOS5)
+ c = KEY_LINE_END;
+ else
+ c = KEY_DELETE_RIGHT;
+ break;
+ case wimp_KEY_CONTROL | wimp_KEY_RIGHT: c = KEY_LINE_END; break;
+ case wimp_KEY_CONTROL | wimp_KEY_UP: c = KEY_TEXT_START; break;
+ case wimp_KEY_CONTROL | wimp_KEY_DOWN: c = KEY_TEXT_END; break;
+ case wimp_KEY_SHIFT | wimp_KEY_LEFT: c = KEY_WORD_LEFT ; break;
+ case wimp_KEY_SHIFT | wimp_KEY_RIGHT: c = KEY_WORD_RIGHT; break;
+ case wimp_KEY_SHIFT | wimp_KEY_UP: c = KEY_PAGE_UP; break;
+ case wimp_KEY_SHIFT | wimp_KEY_DOWN: c = KEY_PAGE_DOWN; break;
+ case wimp_KEY_LEFT: c = KEY_LEFT; break;
+ case wimp_KEY_RIGHT: c = KEY_RIGHT; break;
+ case wimp_KEY_UP: c = KEY_UP; break;
+ case wimp_KEY_DOWN: c = KEY_DOWN; break;
+
+ /* editing */
+ case wimp_KEY_CONTROL | wimp_KEY_END:
+ c = KEY_DELETE_LINE_END;
+ break;
+ case wimp_KEY_DELETE:
+ if (ro_gui_ctrl_pressed())
+ c = KEY_DELETE_LINE_START;
+ else if (os_version < RISCOS5)
+ c = KEY_DELETE_LEFT;
+ break;
+
+ default:
+ break;
}
- return;
}
- /* internal drag */
- if (!ro_gui_tree_current_drag_tree->movable)
- return;
- ro_gui_tree_get_tree_coordinates(ro_gui_tree_current_drag_tree,
- drag->final.x0 + 34, drag->final.y0 + 34, &x, &y);
- node = tree_get_link_details(ro_gui_tree_current_drag_tree, x, y, &before);
- tree_move_selected_nodes(ro_gui_tree_current_drag_tree, node, before);
+ if (!(c & IS_WIMP_KEY)) {
+ if (tree_keypress(tv->tree, c))
+ return true;
+ }
+
+ return false;
}
-
-/**
- * Launches all selected nodes.
+/** Respond to a mouse click on a treeview toolbar.
*
- * \param tree the tree to launch all selected nodes for
+ * \param pointer Pointer to the MouseClick Event block.
+ * \return true if the event was handled; else false.
*/
-void ro_gui_tree_launch_selected(struct tree *tree)
+
+bool ro_gui_treeview_toolbar_click(wimp_pointer *pointer)
{
- assert(tree);
+ struct toolbar *tb;
+ ro_treeview *tv;
- if (tree->root->child)
- ro_gui_tree_launch_selected_node(tree, tree->root->child, false);
-}
+ tb = (struct toolbar *) ro_gui_wimp_event_get_user_data(pointer->w);
+ if (tb == NULL) {
+ LOG(("NULL toolbar block for window: 0x%x",
+ (unsigned int) pointer->w));
+ return false;
+ }
+ tv = (ro_treeview *) ro_gui_wimp_event_get_user_data(tb->parent_handle);
+ if (tv == NULL) {
+ LOG(("NULL treeview block for parent window: 0x%x",
+ (unsigned int) tb->parent_handle));
+ return false;
+ }
-/**
- * Launches all selected nodes.
- *
- * \param node the node to launch all selected nodes for
- */
-void ro_gui_tree_launch_selected_node(struct tree *tree, struct node *node,
- bool all)
-{
- for (; node; node = node->next) {
- if (((node->selected) || (all)) && (!node->folder))
- ro_gui_tree_launch_node(tree, node);
- if ((node->child) && ((node->expanded) || (node->selected) | (all)))
- ro_gui_tree_launch_selected_node(tree, node->child,
- (node->selected) | (all));
+ /* \todo -- Handle menu clicks here... */
+
+ /* \todo -- Deal with the editor here... */
+
+ switch (pointer->i) {
+
}
+
+ return true;
}
-
/**
- * Launches a node using all known methods.
+ * Update a treeview to use a new theme.
*
- * \param node the node to launch
- * \return whether the node could be launched
+ * \param *tv Pointer to the treeview to update.
*/
-bool ro_gui_tree_launch_node(struct tree *tree, struct node *node)
+
+void ro_treeview_update_theme(ro_treeview *tv)
{
- struct node_element *element;
+ if (tv != NULL && tv->tb != NULL){
+ /* \todo -- Check for toolbar editing here. */
- assert(node);
+ if (!ro_gui_theme_update_toolbar(NULL, tv->tb)) {
+ ro_gui_theme_destroy_toolbar(tv->tb);
+ tv->tb = NULL;
+ }
- element = tree_find_element(node, TREE_ELEMENT_URL);
- if (element) {
- browser_window_create(element->text, NULL, 0, true, false);
- return true;
- }
+ /* \todo -- Check for toolbar editing here. */
- element = tree_find_element(node, TREE_ELEMENT_SSL);
- if (element) {
- ro_gui_cert_open(tree, node);
- return true;
- }
+ ro_gui_theme_attach_toolbar(tv->tb, tv->w);
+ ro_treeview_set_origin(tv, 0,
+ -(ro_gui_theme_toolbar_height(tv->tb)));
- return false;
+ xwimp_force_redraw(tv->w, 0, tv->extent.y, tv->extent.x, 0);
+ }
}
-int ro_gui_tree_help(int x, int y)
-{
- return -1;
-}
-void ro_gui_tree_update_theme(struct tree *tree)
-{
+#if 0
if ((tree) && (tree->toolbar)) {
if (tree->toolbar->editor)
if (!ro_gui_theme_update_toolbar(NULL, tree->toolbar->editor))
@@ -1621,4 +993,70 @@
tree_resized(tree);
xwimp_force_redraw((wimp_w)tree->handle, 0, -16384, 16384, 16384);
}
+#endif
+
+/**
+ * Return a token identifying the interactive help message for a given cursor
+ * position.
+ *
+ * Currently this is inimplemented.
+ *
+ * \param *message_data Pointer to the Wimp's help message block.
+ * \return Token value (-1 indicates no help available).
+ */
+
+int ro_treeview_get_help(help_full_message_request *message_data)
+{
+ return -1;
}
+
+/**
+ * Convert a content type into an icon name.
+ *
+ * \todo -- Currently we don't have any icons apart from the default.
+ *
+ * \param *buffer A buffer to return the icon name
+ * \param type The content type to return an icon name for.
+ */
+
+void tree_icon_name_from_content_type(char *buffer, content_type type)
+{
+ switch (type) {
+ case CONTENT_HTML:
+ case CONTENT_TEXTPLAIN:
+ case CONTENT_CSS:
+#if defined(WITH_MNG) || defined(WITH_PNG)
+ case CONTENT_PNG:
+#endif
+#ifdef WITH_MNG
+ case CONTENT_JNG:
+ case CONTENT_MNG:
+#endif
+#ifdef WITH_JPEG
+ case CONTENT_JPEG:
+#endif
+#ifdef WITH_GIF
+ case CONTENT_GIF:
+#endif
+#ifdef WITH_BMP
+ case CONTENT_BMP:
+ case CONTENT_ICO:
+#endif
+#ifdef WITH_SPRITE
+ case CONTENT_SPRITE:
+#endif
+#ifdef WITH_DRAW
+ case CONTENT_DRAW:
+#endif
+#ifdef WITH_ARTWORKS
+ case CONTENT_ARTWORKS:
+#endif
+#ifdef WITH_NS_SVG
+ case CONTENT_SVG:
+#endif
+ default:
+ sprintf(buffer, tree_content_icon_name);
+ break;
+ }
+}
+
Index: riscos/treeview.h
===================================================================
--- riscos/treeview.h (revision 10834)
+++ riscos/treeview.h (working copy)
@@ -1,5 +1,6 @@
/*
* Copyright 2004 Richard Wilson <not_ginger_matt(a)users.sourceforge.net>
+ * Copyright 2010 Stephen Fryatt <stevef(a)netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -24,38 +25,30 @@
#define _NETSURF_RISCOS_TREEVIEW_H_
#include <stdbool.h>
-#include "oslib/osspriteop.h"
-#include "oslib/wimp.h"
+#include <oslib/help.h>
+#include <oslib/wimp.h>
+
#include "desktop/tree.h"
-#include "image/bitmap.h"
-#define TREE_TEXT_HEIGHT 40
-#define TREE_SPRITE_WIDTH 40 /* text plus sprite entries only */
+typedef struct ro_treeview ro_treeview;
-struct node_sprite {
- osspriteop_area *area;
- char name[12];
- char expanded_name[12];
+struct ro_treeview_table {
+ void (*open_menu)(wimp_pointer *pointer);
};
-bool ro_gui_tree_initialise(void);
-void ro_gui_tree_redraw(wimp_draw *redraw);
-bool ro_gui_tree_click(wimp_pointer *pointer, struct tree *tree);
-void ro_gui_tree_menu_closed(struct tree *tree);
-bool ro_gui_tree_toolbar_click(wimp_pointer* pointer);
-void ro_gui_tree_stop_edit(struct tree *tree);
-void ro_gui_tree_open(wimp_open *open);
-void ro_gui_tree_show(struct tree *tree);
-bool ro_gui_tree_keypress(wimp_key *key);
-void ro_gui_tree_selection_drag_end(wimp_dragged *drag);
-void ro_gui_tree_move_drag_end(wimp_dragged *drag);
-void ro_gui_tree_launch_selected(struct tree *tree);
-void ro_gui_tree_start_edit(struct tree *tree, struct node_element *element,
- wimp_pointer *pointer);
-void ro_gui_tree_scroll_visible(struct tree *tree, struct node_element *element);
-void ro_gui_tree_get_tree_coordinates(struct tree *tree, int x, int y,
- int *tree_x, int *tree_y);
-int ro_gui_tree_help(int x, int y);
-void ro_gui_tree_update_theme(struct tree *tree);
+ro_treeview *ro_treeview_create(wimp_w window, struct toolbar *toolbar,
+ unsigned int flags);
+void ro_treeview_destroy(ro_treeview *tv);
+struct tree *ro_treeview_get_tree(ro_treeview *tv);
+wimp_w ro_treeview_get_window(ro_treeview *tv);
+bool ro_treeview_has_selection(ro_treeview *tv);
+
+void ro_treeview_set_origin(ro_treeview *tv, int x, int y);
+void ro_treeview_mouse_at(wimp_w w, wimp_pointer *pointer);
+bool ro_gui_treeview_toolbar_click(wimp_pointer *pointer);
+void ro_treeview_update_theme(ro_treeview *tv);
+int ro_treeview_get_help(help_full_message_request *message_data);
+
#endif
+
Index: riscos/configure/con_home.c
===================================================================
--- riscos/configure/con_home.c (revision 10834)
+++ riscos/configure/con_home.c (working copy)
@@ -22,6 +22,7 @@
#include "riscos/gui.h"
#include "riscos/menus.h"
#include "riscos/options.h"
+#include "riscos/url_suggest.h"
#include "riscos/wimp.h"
#include "riscos/wimp_event.h"
#include "riscos/configure.h"
@@ -42,16 +43,13 @@
bool ro_gui_options_home_initialise(wimp_w w)
{
- int suggestions;
-
/* set the current values */
ro_gui_set_icon_string(w, HOME_URL_FIELD,
option_homepage_url ? option_homepage_url : "", true);
ro_gui_set_icon_selected_state(w, HOME_OPEN_STARTUP,
option_open_browser_at_startup);
- global_history_get_recent(&suggestions);
ro_gui_set_icon_shaded_state(w,
- HOME_URL_GRIGHT, (suggestions <= 0));
+ HOME_URL_GRIGHT, !ro_gui_url_suggest_prepare_menu());
/* initialise all functions for a newly created window */
ro_gui_wimp_event_register_menu_gright(w, HOME_URL_FIELD,
Index: riscos/save.c
===================================================================
--- riscos/save.c (revision 10834)
+++ riscos/save.c (working copy)
@@ -37,6 +37,8 @@
#include "oslib/wimpspriteop.h"
#include "content/content.h"
#include "content/hlcache.h"
+#include "desktop/hotlist.h"
+#include "desktop/history_global_core.h"
#include "desktop/netsurf.h"
#include "desktop/save_complete.h"
#include "desktop/save_text.h"
@@ -630,9 +632,9 @@
while (!dest_ok && (box = box_at_point(box,
pos.x, pos.y, &box_x, &box_y,
&h))) {
- if (box->style &&
+ if (box->style &&
css_computed_visibility(
- box->style) ==
+ box->style) ==
CSS_VISIBILITY_HIDDEN)
continue;
@@ -897,8 +899,7 @@
LINK_TEXT, path);
case GUI_SAVE_HOTLIST_EXPORT_HTML:
- if (!options_save_tree(hotlist_tree, path,
- "NetSurf hotlist"))
+ if (!hotlist_export(path))
return false;
error = xosfile_set_type(path, 0xfaf);
if (error)
@@ -906,8 +907,7 @@
error->errnum, error->errmess));
break;
case GUI_SAVE_HISTORY_EXPORT_HTML:
- if (!options_save_tree(global_history_tree, path,
- "NetSurf history"))
+ if (!history_global_export(path))
return false;
error = xosfile_set_type(path, 0xfaf);
if (error)
@@ -1346,7 +1346,7 @@
}
/* leafname */
- if (url && url_nice(url, &nice, option_strip_extensions) ==
+ if (url && url_nice(url, &nice, option_strip_extensions) ==
URL_FUNC_OK) {
for (i = 0; nice[i]; i++) {
if (nice[i] == '.')
Index: riscos/window.c
===================================================================
--- riscos/window.c (revision 10834)
+++ riscos/window.c (working copy)
@@ -5,6 +5,7 @@
* Copyright 2004 Andrew Timmins <atimmins(a)blueyonder.co.uk>
* Copyright 2005 Richard Wilson <info(a)tinct.net>
* Copyright 2005 Adrian Lees <adrianl(a)users.sourceforge.net>
+ * Copyright 2010 Stephen Fryatt <stevef(a)netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -150,7 +151,6 @@
static void ro_gui_window_launch_url(struct gui_window *g, const char *url);
static void ro_gui_window_clone_options(struct browser_window *new_bw,
struct browser_window *old_bw);
-static browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons);
static bool ro_gui_window_import_text(struct gui_window *g,
const char *filename, bool toolbar);
@@ -398,7 +398,7 @@
state.next = wimp_TOP;
if (bw->parent) {
top = browser_window_owner(bw);
- error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state),
+ error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state),
top->window->window,
wimp_CHILD_LINKS_PARENT_WORK_AREA
<< wimp_CHILD_XORIGIN_SHIFT |
@@ -1110,7 +1110,7 @@
* set favicon
*/
void gui_window_set_icon(struct gui_window *g, hlcache_handle *icon)
-{
+{
}
/**
@@ -1688,7 +1688,6 @@
if (res == URL_FUNC_OK) {
gui_window_set_url(g, url_norm);
browser_window_go(g->bw, url_norm, 0, true);
- global_history_add_recent(url_norm);
free(url_norm);
}
}
@@ -2124,7 +2123,8 @@
if (ro_gui_window_to_window_pos(g, pointer->pos.x, pointer->pos.y, &pos))
browser_window_mouse_track(g->bw,
- ro_gui_mouse_drag_state(pointer->buttons),
+ ro_gui_mouse_drag_state(pointer->buttons,
+ wimp_BUTTON_CLICK_DRAG),
pos.x, pos.y);
}
@@ -2321,7 +2321,8 @@
} else {
if (ro_gui_window_to_window_pos(g, pointer->pos.x, pointer->pos.y, &pos))
browser_window_mouse_click(g->bw,
- ro_gui_mouse_click_state(pointer->buttons),
+ ro_gui_mouse_click_state(pointer->buttons,
+ wimp_BUTTON_CLICK_DRAG),
pos.x, pos.y);
}
return true;
@@ -3088,17 +3089,35 @@
/**
* Returns the state of the mouse buttons and modifiers keys for a
* click/release action, suitable for passing to the OS-independent
- * browser window code
+ * browser window/ treeview/ etc code.
+ *
+ * \param buttons Wimp button state.
+ * \param type Wimp work-area/icon type for decoding.
+ * \return NetSurf core button state.
*/
-browser_mouse_state ro_gui_mouse_click_state(wimp_mouse_state buttons)
+browser_mouse_state ro_gui_mouse_click_state(wimp_mouse_state buttons,
+ wimp_icon_flags type)
{
browser_mouse_state state = 0;
- if (buttons & (wimp_CLICK_SELECT))
- state |= BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1;
- if (buttons & (wimp_CLICK_ADJUST))
- state |= BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_CLICK_2;
+ switch (type) {
+ case wimp_BUTTON_CLICK_DRAG:
+ if (buttons & (wimp_CLICK_SELECT))
+ state |= BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1;
+ if (buttons & (wimp_CLICK_ADJUST))
+ state |= BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_CLICK_2;
+ break;
+ case wimp_BUTTON_DOUBLE_CLICK_DRAG:
+ if (buttons & (wimp_SINGLE_SELECT))
+ state |= BROWSER_MOUSE_CLICK_1;
+ if (buttons & (wimp_SINGLE_ADJUST))
+ state |= BROWSER_MOUSE_CLICK_2;
+ if (buttons & (wimp_DOUBLE_SELECT))
+ state |= BROWSER_MOUSE_CLICK_1 |
+ BROWSER_MOUSE_DOUBLE_CLICK;
+ break;
+ }
if (buttons & (wimp_DRAG_SELECT)) {
state |= BROWSER_MOUSE_DRAG_1;
@@ -3111,30 +3130,46 @@
if (ro_gui_shift_pressed()) state |= BROWSER_MOUSE_MOD_1;
if (ro_gui_ctrl_pressed()) state |= BROWSER_MOUSE_MOD_2;
+ if (ro_gui_alt_pressed()) state |= BROWSER_MOUSE_MOD_3;
return state;
}
-
/**
* Returns the state of the mouse buttons and modifiers keys whilst
- * dragging, for passing to the OS-independent browser window code
+ * dragging, for passing to the OS-independent browser window/ treeview/
+ * etc code
+ *
+ * \param buttons Wimp button state.
+ * \param type Wimp work-area/icon type for decoding.
+ * \return NetSurf core button state.
*/
-browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons)
+browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons,
+ wimp_icon_flags type)
{
browser_mouse_state state = 0;
+ switch (type) {
+ case wimp_BUTTON_CLICK_DRAG:
+ case wimp_BUTTON_DOUBLE_CLICK_DRAG:
+ if (buttons & (wimp_CLICK_SELECT))
+ state |= BROWSER_MOUSE_HOLDING_1;
+ if (buttons & (wimp_CLICK_ADJUST))
+ state |= BROWSER_MOUSE_HOLDING_2;
- if (buttons & (wimp_CLICK_SELECT)) state |= BROWSER_MOUSE_HOLDING_1;
- if (buttons & (wimp_CLICK_ADJUST)) state |= BROWSER_MOUSE_HOLDING_2;
+ if (!(buttons & (wimp_CLICK_SELECT) ||
+ buttons & (wimp_CLICK_ADJUST)))
+ mouse_drag = false;
+ break;
+ }
- if (!(buttons & (wimp_CLICK_SELECT) || buttons & (wimp_CLICK_ADJUST)))
- mouse_drag = false;
- if (mouse_drag) state |= BROWSER_MOUSE_DRAG_ON;
+ if (mouse_drag)
+ state |= BROWSER_MOUSE_DRAG_ON;
if (ro_gui_shift_pressed()) state |= BROWSER_MOUSE_MOD_1;
if (ro_gui_ctrl_pressed()) state |= BROWSER_MOUSE_MOD_2;
+ if (ro_gui_alt_pressed()) state |= BROWSER_MOUSE_MOD_3;
return state;
}
@@ -3216,7 +3251,8 @@
if (ro_gui_window_to_window_pos(g, drag->final.x0, drag->final.y0, &pos))
browser_window_mouse_drag_end(g->bw,
- ro_gui_mouse_click_state(pointer.buttons),
+ ro_gui_mouse_click_state(pointer.buttons,
+ wimp_BUTTON_CLICK_DRAG),
pos.x, pos.y);
}
Index: riscos/wimp_event.c
===================================================================
--- riscos/wimp_event.c (revision 10834)
+++ riscos/wimp_event.c (working copy)
@@ -1,5 +1,6 @@
/*
* Copyright 2005 Richard Wilson <info(a)tinct.net>
+ * Copyright 2010 Stephen Fryatt <stevef(a)netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -95,6 +96,14 @@
void (*close_window)(wimp_w w);
void (*redraw_window)(wimp_draw *redraw);
void (*menu_selection)(wimp_w w, wimp_i i);
+ wimp_menu *window_menu;
+ bool window_menu_auto;
+ void (*window_menu_prepare)(wimp_w w, wimp_menu *m);
+ bool (*window_menu_selection)(wimp_w w, wimp_menu *m,
+ wimp_selection *s, menu_action action);
+ void (*window_menu_close)(wimp_w w, wimp_menu *m);
+ void (*window_menu_warning)(wimp_w w, wimp_menu *m,
+ wimp_selection *s, menu_action action);
const char *help_prefix;
void *user_data;
struct icon_event *first;
@@ -345,14 +354,27 @@
/**
* Handles a menu selection event.
*
+ * (At present, this is tied to being called from menus.c and relies on that
+ * module decoding the menu into an action code. If menus.c loses its
+ * menu handling in the future, such decoding might need to move here.)
+ *
+ * The order of execution is:
+ *
+ * 1. Try to match the menu to a pop-up menu. If successful, handle it as
+ * this.
+ * 2. Try to match the menu to a window menu. If successful, pass control to
+ * the menu's registered _select handler.
+ * 3. Return event as unhandled.
+ *
* \param w the window to owning the menu
* \param i the icon owning the menu
* \param menu the menu that has been selected
* \param selection the selection information
- * \return true if the event was handled, false otherwise
+ * \param action the menu action info from menus.c
+ * \return true if the event was handled, false otherwise
*/
bool ro_gui_wimp_event_menu_selection(wimp_w w, wimp_i i, wimp_menu *menu,
- wimp_selection *selection)
+ wimp_selection *selection, menu_action action)
{
struct event_window *window;
struct icon_event *event;
@@ -367,12 +389,29 @@
if (!window)
return false;
+ /* Start by looking for an icon event that matches. If there isn't one,
+ * then check to see if there is a window menu and associated
+ * selection handler available instead.
+ */
+
for (event = window->first; event; event = event->next)
if ((event->type == EVENT_MENU_GRIGHT) && (event->i == i))
break;
- if (!event)
- return false;
+ if (!event) {
+ if ((window->window_menu) && (window->window_menu == menu)
+ && (window->window_menu_selection)) {
+ window->window_menu_selection(w, menu,
+ selection, action);
+ /* Prepare the menu pending a possible Adjust click. */
+ if (window->window_menu_prepare)
+ window->window_menu_prepare(w, menu);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
menu_entry = &menu->entries[selection->items[0]];
for (i = 1; selection->items[i] != -1; i++)
menu_entry = &menu_entry->sub_menu->
@@ -433,10 +472,12 @@
*
* The order of execution is:
*
- * 1. Any registered mouse_click routine (see ro_gui_wimp_register_mouse_click())
- * 2. If the current icon is not registered with a type then it is assumed that no
+ * 1. If a menu click, and the window has an automatic window menu, this is
+ * processed immediately.
+ * 2. Any registered mouse_click routine (see ro_gui_wimp_register_mouse_click())
+ * 3. If the current icon is not registered with a type then it is assumed that no
* action is necessary, and the click is deemed to have been handled.
- * 3. If the registered mouse_click routine returned false, or there was no registered
+ * 4. If the registered mouse_click routine returned false, or there was no registered
* routine then the automated action for the registered icon type is performed
*
* \param pointer the current pointer state
@@ -458,7 +499,13 @@
if (!window)
return false;
- /* registered routines take priority */
+ /* Menu clicks take priority if there is an auto menu defined. */
+ if ((window->window_menu) && (window->window_menu_auto)) {
+ ro_gui_wimp_event_process_window_menu_click(pointer);
+ return true;
+ }
+
+ /* registered routines take next priority */
if ((window->mouse_click) && (window->mouse_click(pointer)))
return true;
@@ -919,6 +966,32 @@
/**
+ * Process a Menu click in a window, by checking for a registered window
+ * menu and opening it if one is found.
+ *
+ * \param *p The pointer block from the mouse click event.
+ * \return true if the click was actioned; else false.
+ */
+
+bool ro_gui_wimp_event_process_window_menu_click(wimp_pointer *pointer)
+{
+ struct event_window *window;
+
+ window = ro_gui_wimp_event_find_window(pointer->w);
+ if ((window) && (window->window_menu)
+ && (pointer->buttons == wimp_CLICK_MENU)) {
+ if (window->window_menu_prepare)
+ window->window_menu_prepare(window->w,
+ window->window_menu);
+
+ ro_gui_menu_create(window->window_menu,
+ pointer->pos.x, pointer->pos.y, window->w);
+ return true;
+ }
+ return false;
+}
+
+/**
* Register a numeric field to be automatically handled
*/
bool ro_gui_wimp_event_register_numeric_field(wimp_w w, wimp_i i,
@@ -1168,9 +1241,39 @@
return true;
}
+/**
+ * Register a set of functions to be called to handle a window menu.
+ *
+ * \param
+ */
+bool ro_gui_wimp_event_register_window_menu(wimp_w w, wimp_menu *m,
+ void (*callback_prepare)(wimp_w w, wimp_menu *m),
+ bool (*callback_selection)(wimp_w w, wimp_menu *m,
+ wimp_selection *s, menu_action action),
+ void (*callback_close)(wimp_w w, wimp_menu *m),
+ void (*callback_warning)(wimp_w w, wimp_menu *m,
+ wimp_selection *s, menu_action action),
+ bool menu_auto)
+{
+ struct event_window *window;
+
+ window = ro_gui_wimp_event_get_window(w);
+ if (!window)
+ return false;
+ window->window_menu = m;
+ window->window_menu_prepare = callback_prepare;
+ window->window_menu_selection = callback_selection;
+ window->window_menu_close = callback_close;
+ window->window_menu_warning = callback_warning;
+ window->window_menu_auto = menu_auto;
+ return true;
+}
+
+
/**
- * Finds the event data associated with a given window handle, or creates a new one.
+ * Finds the event data associated with a given window handle, or creates a
+ * new one.
*
* \param w the window to find data for
*/
@@ -1273,12 +1376,88 @@
return event;
}
+/* Handle sumbenu warnings. This is called from ro_gui_menu_warning(), and
+ * returns to that function to have the submenu opened correctly.
+ *
+ * \param w the window to owning the menu
+ * \param i the icon owning the menu
+ * \param menu the menu that has been selected
+ * \param selection the selection information
+ * \param action the menu action info from menus.c
+ * \return true if the event was handled, false otherwise
+ */
+
+bool ro_gui_wimp_event_submenu_warning(wimp_w w, wimp_i i, wimp_menu *menu,
+ wimp_selection *selection, menu_action action)
+{
+ struct event_window *window;
+ struct icon_event *event;
+
+ ro_gui_wimp_event_register_submenu(0);
+
+ /* Process the event for any window menus. Find the window data, then
+ * try and match to an icon event. If we can, then there isn't anything
+ * to do.
+ */
+
+ window = ro_gui_wimp_event_find_window(w);
+ if (!window)
+ return false;
+
+ for (event = window->first; event; event = event->next)
+ if ((event->type == EVENT_MENU_GRIGHT) && (event->i == i))
+ break;
+ if (event)
+ return false;
+
+ /* If the warning is for a window menu, then pass the event on to it. */
+
+ if ((window->window_menu) && (window->window_menu == menu)) {
+ if (window->window_menu_warning) {
+ window->window_menu_warning(w, menu, selection, action);
+ return true;
+ }
+ }
+
+ return false;
+}
+
/**
- * Handle menus being closed
+ * Handle menus being closed. This is called from ro_gui_menu_closed(), in
+ * every scenario when one of our own menus is open.
+ *
+ * \param w the window to owning the menu
+ * \param i the icon owning the menu
+ * \param menu the menu that has been selected
*/
-void ro_gui_wimp_event_menus_closed(void)
+
+void ro_gui_wimp_event_menus_closed(wimp_w w, wimp_i i, wimp_menu *menu)
{
- ro_gui_wimp_event_register_submenu(0);
+ struct event_window *window;
+ struct icon_event *event;
+
+ ro_gui_wimp_event_register_submenu(0);
+
+ /* Process the event for any window menus. Find the window data, then
+ * try and match to an icon event. If we can, then there isn't anything
+ * to do.
+ */
+
+ window = ro_gui_wimp_event_find_window(w);
+ if (!window)
+ return;
+
+ for (event = window->first; event; event = event->next)
+ if ((event->type == EVENT_MENU_GRIGHT) && (event->i == i))
+ break;
+ if (event)
+ return;
+
+ /* If the close is for a window menu, then pass the event on to it. */
+
+ if ((window->window_menu) && (window->window_menu == menu) &&
+ (window->window_menu_close))
+ window->window_menu_close(w, menu);
}
/**
Index: riscos/wimp_event.h
===================================================================
--- riscos/wimp_event.h (revision 10834)
+++ riscos/wimp_event.h (working copy)
@@ -1,5 +1,6 @@
/*
* Copyright 2005 Richard Wilson <info(a)tinct.net>
+ * Copyright 2010 Stephen Fryatt <stevef(a)netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -30,7 +31,8 @@
#include <stdio.h>
#include <string.h>
#include "oslib/os.h"
-#include "oslib/wimp.h"
+#include "oslib/wimp.h"
+#include "riscos/menus.h"
#define IS_WIMP_KEY (1u<<31)
@@ -45,12 +47,14 @@
void *ro_gui_wimp_event_get_user_data(wimp_w w);
bool ro_gui_wimp_event_menu_selection(wimp_w w, wimp_i i, wimp_menu *menu,
- wimp_selection *selection);
+ wimp_selection *selection, menu_action action);
bool ro_gui_wimp_event_mouse_click(wimp_pointer *pointer);
bool ro_gui_wimp_event_keypress(wimp_key *key);
bool ro_gui_wimp_event_open_window(wimp_open *open);
bool ro_gui_wimp_event_close_window(wimp_w w);
-bool ro_gui_wimp_event_redraw_window(wimp_draw *redraw);
+bool ro_gui_wimp_event_redraw_window(wimp_draw *redraw);
+
+bool ro_gui_wimp_event_process_window_menu_click(wimp_pointer *pointer);
bool ro_gui_wimp_event_register_numeric_field(wimp_w w, wimp_i i, wimp_i up,
wimp_i down, int min, int max, int stepping,
@@ -78,8 +82,18 @@
void (*callback)(wimp_draw *redraw));
bool ro_gui_wimp_event_register_menu_selection(wimp_w w,
void (*callback)(wimp_w w, wimp_i i));
+bool ro_gui_wimp_event_register_window_menu(wimp_w w, wimp_menu *m,
+ void (*callback_prepare)(wimp_w w, wimp_menu *m),
+ bool (*callback_selection)(wimp_w w, wimp_menu *m,
+ wimp_selection *s, menu_action action),
+ void (*callback_close)(wimp_w w, wimp_menu *m),
+ void (*callback_warning)(wimp_w w, wimp_menu *m,
+ wimp_selection *s, menu_action action),
+ bool menu_auto);
-void ro_gui_wimp_event_menus_closed(void);
+bool ro_gui_wimp_event_submenu_warning(wimp_w w, wimp_i i, wimp_menu *menu,
+ wimp_selection *selection, menu_action action);
+void ro_gui_wimp_event_menus_closed(wimp_w w, wimp_i i, wimp_menu *menu);
void ro_gui_wimp_event_register_submenu(wimp_w w);
#endif
Index: riscos/menus.c
===================================================================
--- riscos/menus.c (revision 10834)
+++ riscos/menus.c (working copy)
@@ -34,9 +34,12 @@
#include "content/content.h"
#include "content/hlcache.h"
#include "content/urldb.h"
+#include "desktop/cookies.h"
#include "desktop/browser.h"
#include "desktop/gui.h"
+#include "desktop/history_global_core.h"
#include "desktop/history_core.h"
+#include "desktop/hotlist.h"
#include "desktop/netsurf.h"
#include "desktop/selection.h"
#include "desktop/textinput.h"
@@ -49,12 +52,14 @@
#include "riscos/gui.h"
#include "riscos/global_history.h"
#include "riscos/help.h"
+#include "riscos/hotlist.h"
#include "riscos/menus.h"
#include "riscos/options.h"
#include "riscos/save.h"
#include "riscos/tinct.h"
#include "riscos/theme.h"
#include "riscos/treeview.h"
+#include "riscos/url_suggest.h"
#include "riscos/wimp.h"
#include "riscos/wimp_event.h"
#include "utils/log.h"
@@ -63,18 +68,6 @@
#include "utils/utils.h"
#include "utils/utf8.h"
-
-struct ns_menu_entry {
- const char *text; /**< menu text (from messages) */
- menu_action action; /**< associated action */
- wimp_w *sub_window; /**< sub-window if any */
-};
-
-struct ns_menu {
- const char *title;
- struct ns_menu_entry entries[];
-};
-
struct menu_definition_entry {
menu_action action; /**< menu action */
wimp_menu_entry *menu_entry; /**< corresponding menu entry */
@@ -91,7 +84,6 @@
};
-static wimp_menu *ro_gui_menu_define_menu(const struct ns_menu *menu);
static void ro_gui_menu_define_menu_add(struct menu_definition *definition,
const struct ns_menu *menu, int depth,
wimp_menu_entry *parent_entry,
@@ -101,15 +93,11 @@
menu_action action);
static menu_action ro_gui_menu_find_action(wimp_menu *menu,
wimp_menu_entry *menu_entry);
-static void ro_gui_menu_set_entry_shaded(wimp_menu *menu, menu_action action,
- bool shaded);
-static void ro_gui_menu_set_entry_ticked(wimp_menu *menu, menu_action action,
- bool ticked);
static void ro_gui_menu_get_window_details(wimp_w w, struct gui_window **g,
struct browser_window **bw, hlcache_handle **h,
- struct toolbar **toolbar, struct tree **tree);
+ struct toolbar **toolbar,
+ bool *is_cookies, bool *is_hotlist, bool *is_global_history);
static int ro_gui_menu_get_checksum(void);
-static bool ro_gui_menu_prepare_url_suggest(void);
static void ro_gui_menu_prepare_pageinfo(struct gui_window *g);
static void ro_gui_menu_prepare_objectinfo(hlcache_handle *object,
const char *href);
@@ -143,13 +131,13 @@
/** The height of the iconbar menu */
int iconbar_menu_height = 5 * 44;
/** The available menus */
-wimp_menu *iconbar_menu, *browser_menu, *hotlist_menu, *global_history_menu, *cookies_menu,
- *image_quality_menu, *browser_toolbar_menu,
- *tree_toolbar_menu, *proxy_type_menu, *languages_menu;
-/** URL suggestion menu */
-static wimp_MENU(GLOBAL_HISTORY_RECENT_URLS) url_suggest;
-wimp_menu *url_suggest_menu = (wimp_menu *)&url_suggest;
+wimp_menu *iconbar_menu, *browser_menu, *image_quality_menu,
+ *browser_toolbar_menu, *tree_toolbar_menu,
+ *proxy_type_menu, *languages_menu;
+static wimp_MENU(URL_SUGGEST_MAX_URLS) url_suggest_menu_block;
+wimp_menu *url_suggest_menu = (wimp_menu *) &url_suggest_menu_block;
+
/* the values given in PRM 3-157 for how to check menus/windows are
* incorrect so we use a hack of checking if the sub-menu has bit 0
* set which is undocumented but true of window handles on
@@ -277,94 +265,6 @@
};
browser_menu = ro_gui_menu_define_menu(&browser_definition);
- /* hotlist menu */
- static wimp_w one = (wimp_w) 1;
- static const struct ns_menu hotlist_definition = {
- "Hotlist", {
- { "Hotlist", NO_ACTION, 0 },
- { "Hotlist.New", NO_ACTION, 0 },
- { "Hotlist.New.Folder", TREE_NEW_FOLDER, &dialog_folder },
- { "Hotlist.New.Link", TREE_NEW_LINK, &dialog_entry },
- { "_Hotlist.Export", HOTLIST_EXPORT, &dialog_saveas },
- { "Hotlist.Expand", TREE_EXPAND_ALL, 0 },
- { "Hotlist.Expand.All", TREE_EXPAND_ALL, 0 },
- { "Hotlist.Expand.Folders", TREE_EXPAND_FOLDERS, 0 },
- { "Hotlist.Expand.Links", TREE_EXPAND_LINKS, 0 },
- { "Hotlist.Collapse", TREE_COLLAPSE_ALL, 0 },
- { "Hotlist.Collapse.All", TREE_COLLAPSE_ALL, 0 },
- { "Hotlist.Collapse.Folders", TREE_COLLAPSE_FOLDERS, 0 },
- { "Hotlist.Collapse.Links", TREE_COLLAPSE_LINKS, 0 },
- { "Hotlist.Toolbars", NO_ACTION, 0 },
- { "_Hotlist.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 },
- { "Hotlist.Toolbars.EditToolbar", TOOLBAR_EDIT, 0 },
- { "Selection", TREE_SELECTION, 0 },
- /* We want a window, but it changes depending upon
- * context. Therefore, ensure that the structure is
- * created so that we can dynamically modify the
- * actual item presented. We do this by creating a
- * fake wimp_w with the value 1, which indicates a
- * window handle as opposed to a submenu. */
- { "Selection.Edit", TREE_SELECTION_EDIT, &one },
- { "Selection.Launch", TREE_SELECTION_LAUNCH, 0 },
- { "Selection.Delete", TREE_SELECTION_DELETE, 0 },
- { "SelectAll", TREE_SELECT_ALL, 0 },
- { "Clear", TREE_CLEAR_SELECTION, 0 },
- {NULL, 0, 0}
- }
- };
- hotlist_menu = ro_gui_menu_define_menu(&hotlist_definition);
-
- /* history menu */
- static const struct ns_menu global_history_definition = {
- "History", {
- { "History", NO_ACTION, 0 },
- { "_History.Export", HISTORY_EXPORT, &dialog_saveas },
- { "History.Expand", TREE_EXPAND_ALL, 0 },
- { "History.Expand.All", TREE_EXPAND_ALL, 0 },
- { "History.Expand.Folders", TREE_EXPAND_FOLDERS, 0 },
- { "History.Expand.Links", TREE_EXPAND_LINKS, 0 },
- { "History.Collapse", TREE_COLLAPSE_ALL, 0 },
- { "History.Collapse.All", TREE_COLLAPSE_ALL, 0 },
- { "History.Collapse.Folders", TREE_COLLAPSE_FOLDERS, 0 },
- { "History.Collapse.Links", TREE_COLLAPSE_LINKS, 0 },
- { "History.Toolbars", NO_ACTION, 0 },
- { "_History.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 },
- { "History.Toolbars.EditToolbar",TOOLBAR_EDIT, 0 },
- { "Selection", TREE_SELECTION, 0 },
- { "Selection.Launch", TREE_SELECTION_LAUNCH, 0 },
- { "Selection.Delete", TREE_SELECTION_DELETE, 0 },
- { "SelectAll", TREE_SELECT_ALL, 0 },
- { "Clear", TREE_CLEAR_SELECTION, 0 },
- {NULL, 0, 0}
- }
- };
- global_history_menu = ro_gui_menu_define_menu(
- &global_history_definition);
-
- /* history menu */
- static const struct ns_menu cookies_definition = {
- "Cookies", {
- { "Cookies", NO_ACTION, 0 },
- { "Cookies.Expand", TREE_EXPAND_ALL, 0 },
- { "Cookies.Expand.All", TREE_EXPAND_ALL, 0 },
- { "Cookies.Expand.Folders", TREE_EXPAND_FOLDERS, 0 },
- { "Cookies.Expand.Links", TREE_EXPAND_LINKS, 0 },
- { "Cookies.Collapse", TREE_COLLAPSE_ALL, 0 },
- { "Cookies.Collapse.All", TREE_COLLAPSE_ALL, 0 },
- { "Cookies.Collapse.Folders", TREE_COLLAPSE_FOLDERS, 0 },
- { "Cookies.Collapse.Links", TREE_COLLAPSE_LINKS, 0 },
- { "Cookies.Toolbars", NO_ACTION, 0 },
- { "_Cookies.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 },
- { "Cookies.Toolbars.EditToolbar",TOOLBAR_EDIT, 0 },
- { "Selection", TREE_SELECTION, 0 },
- { "Selection.Delete", TREE_SELECTION_DELETE, 0 },
- { "SelectAll", TREE_SELECT_ALL, 0 },
- { "Clear", TREE_CLEAR_SELECTION, 0 },
- {NULL, 0, 0}
- }
- };
- cookies_menu = ro_gui_menu_define_menu(&cookies_definition);
-
/* image quality menu */
static const struct ns_menu images_definition = {
"Display", {
@@ -415,9 +315,7 @@
proxy_type_menu = ro_gui_menu_define_menu(&proxy_type_definition);
/* special case menus */
- url_suggest_menu->title_data.indirected_text.text =
- (char *) messages_get("URLSuggest");
- ro_gui_menu_init_structure(url_suggest_menu, GLOBAL_HISTORY_RECENT_URLS);
+ ro_gui_url_suggest_init(url_suggest_menu);
/* Note: This table *must* be kept in sync with the LangNames file */
static const struct ns_menu lang_definition = {
@@ -540,7 +438,7 @@
/* prepare the menu state */
if (menu == url_suggest_menu) {
- if (!ro_gui_menu_prepare_url_suggest())
+ if (!ro_gui_url_suggest_prepare_menu())
return;
} else if (menu == recent_search_menu) {
if (!ro_gui_search_prepare_menu())
@@ -618,8 +516,8 @@
struct browser_window *bw;
hlcache_handle *h;
struct toolbar *t;
- struct tree *tree;
os_error *error;
+ bool is_cookies, is_hotlist, is_global_history;
if (current_menu) {
@@ -630,15 +528,16 @@
warn_user("MenuError", error->errmess);
}
ro_gui_menu_get_window_details(current_menu_window,
- &g, &bw, &h, &t, &tree);
- current_menu = NULL;
+ &g, &bw, &h, &t,
+ &is_cookies, &is_hotlist,
+ &is_global_history);
if (cleanup) {
- ro_gui_wimp_event_menus_closed();
-
- if (tree)
- ro_gui_tree_menu_closed(tree);
+ ro_gui_wimp_event_menus_closed(current_menu_window,
+ current_menu_icon, current_menu);
}
+
+ current_menu = NULL;
}
current_menu_window = NULL;
@@ -668,15 +567,16 @@
*/
void ro_gui_menu_selection(wimp_selection *selection)
{
- int i, j;
- wimp_menu_entry *menu_entry;
- menu_action action;
- wimp_pointer pointer;
- struct gui_window *g = NULL;
- wimp_menu *menu;
- os_error *error;
- int previous_menu_icon = current_menu_icon;
- char *url;
+ int i, j;
+ bool needs_prepare;
+ wimp_menu_entry *menu_entry;
+ menu_action action;
+ wimp_pointer pointer;
+ struct gui_window *g = NULL;
+ wimp_menu *menu;
+ os_error *error;
+ int previous_menu_icon = current_menu_icon;
+ char *url;
/* if we are using gui_multitask then menu selection events
* may be delivered after the menu has been closed. As such,
@@ -686,42 +586,59 @@
assert(current_menu_window);
- /* get the menu entry and associated action */
+ /* get the menu entry and associated action and definition */
menu_entry = ¤t_menu->entries[selection->items[0]];
for (i = 1; selection->items[i] != -1; i++)
menu_entry = &menu_entry->sub_menu->
entries[selection->items[i]];
action = ro_gui_menu_find_action(current_menu, menu_entry);
- /* perform menu action */
- if (action != NO_ACTION)
- ro_gui_menu_handle_action(current_menu_window, action, false);
+ /* Deal with the menu action. We first pass it to Wimp_Event to
+ * handle any automatic menus. If this doesn't recognise the details,
+ * it is passed on to the code in menus.c.
+ */
- /* perform non-automated actions */
- if (current_menu == url_suggest_menu) {
- g = ro_gui_toolbar_lookup(current_menu_window);
- if (g) {
- url = url_suggest_menu->entries[selection->items[0]].
- data.indirected_text.text;
- gui_window_set_url(g, url);
- browser_window_go(g->bw, url, 0, true);
- global_history_add_recent(url);
- }
- } else if (current_menu == gui_form_select_menu) {
- g = ro_gui_window_lookup(current_menu_window);
- assert(g);
+ needs_prepare = false;
- if (selection->items[0] >= 0) {
- form_select_process_selection(g->bw->current_content,
- gui_form_select_control,
- selection->items[0]);
+ if (!ro_gui_wimp_event_menu_selection(current_menu_window,
+ current_menu_icon, current_menu, selection, action)) {
+
+ /* perform menu action */
+ if (action != NO_ACTION)
+ ro_gui_menu_handle_action(current_menu_window,
+ action, false);
+
+ /* perform non-automated actions */
+ if (current_menu == url_suggest_menu) {
+ g = ro_gui_toolbar_lookup(current_menu_window);
+ if (g) {
+ url = url_suggest_menu->entries[selection->items[0]].
+ data.indirected_text.text;
+ gui_window_set_url(g, url);
+ browser_window_go(g->bw, url, 0, true);
+ }
+ } else if (current_menu == gui_form_select_menu) {
+ g = ro_gui_window_lookup(current_menu_window);
+ assert(g);
+
+ if (selection->items[0] >= 0) {
+ form_select_process_selection(g->bw->current_content,
+ gui_form_select_control,
+ selection->items[0]);
+ }
}
- }
- /* allow automatic menus to have their data updated */
- ro_gui_wimp_event_menu_selection(current_menu_window, current_menu_icon,
- current_menu, selection);
+ /* allow automatic menus to have their data updated */
+// ro_gui_wimp_event_menu_selection(current_menu_window,
+// current_menu_icon, current_menu, selection);
+ /* Menus not handled by ro_gui_wimp_event_menu_selection()
+ * will need to be re-prepared before an adjust reopening.
+ */
+
+ needs_prepare = true;
+ }
+
/* re-open the menu for Adjust clicks */
error = xwimp_get_pointer_info(&pointer);
if (error) {
@@ -738,24 +655,26 @@
}
/* re-prepare all the visible entries */
- i = 0;
- menu = current_menu;
- do {
- j = 0;
+ if (needs_prepare) {
+ i = 0;
+ menu = current_menu;
do {
- action = ro_gui_menu_find_action(current_menu,
- &menu->entries[j]);
- if (action != NO_ACTION)
- ro_gui_menu_prepare_action(current_menu_window,
- action, false);
- } while (!(menu->entries[j++].menu_flags & wimp_MENU_LAST));
- j = selection->items[i++];
- if (j != -1) {
- menu = menu->entries[j].sub_menu;
- if ((!menu) || (menu == wimp_NO_SUB_MENU))
- break;
- }
- } while (j != -1);
+ j = 0;
+ do {
+ action = ro_gui_menu_find_action(current_menu,
+ &menu->entries[j]);
+ if (action != NO_ACTION)
+ ro_gui_menu_prepare_action(current_menu_window,
+ action, false);
+ } while (!(menu->entries[j++].menu_flags & wimp_MENU_LAST));
+ j = selection->items[i++];
+ if (j != -1) {
+ menu = menu->entries[j].sub_menu;
+ if ((!menu) || (menu == wimp_NO_SUB_MENU))
+ break;
+ }
+ } while (j != -1);
+ }
if (current_menu == gui_form_select_menu) {
assert(g); /* Keep scan-build happy */
@@ -788,29 +707,43 @@
for (i = 1; warning->selection.items[i] != -1; i++)
menu_entry = &menu_entry->sub_menu->
entries[warning->selection.items[i]];
+ action = ro_gui_menu_find_action(current_menu, menu_entry);
- if (IS_MENU(menu_entry->sub_menu)) {
- ro_gui_wimp_event_register_submenu((wimp_w)0);
- sub_menu = menu_entry->sub_menu;
- i = 0;
- do {
- action = ro_gui_menu_find_action(current_menu,
- &sub_menu->entries[i]);
+ /* We only process the menu in the old way if the wimp_event module
+ * hasn't processed it for us.
+ */
+
+ if (!ro_gui_wimp_event_submenu_warning(current_menu_window,
+ current_menu_icon, current_menu, &(warning->selection),
+ action)) {
+ if (IS_MENU(menu_entry->sub_menu)) {
+ ro_gui_wimp_event_register_submenu((wimp_w)0);
+ sub_menu = menu_entry->sub_menu;
+ i = 0;
+ do {
+ action = ro_gui_menu_find_action(current_menu,
+ &sub_menu->entries[i]);
+ if (action != NO_ACTION)
+ ro_gui_menu_prepare_action(current_menu_window,
+ action, false);
+ } while (!(sub_menu->entries[i++].menu_flags &
+ wimp_MENU_LAST));
+ } else {
+ ro_gui_wimp_event_register_submenu((wimp_w)menu_entry->sub_menu);
+ action = ro_gui_menu_find_action(current_menu, menu_entry);
if (action != NO_ACTION)
ro_gui_menu_prepare_action(current_menu_window,
- action, false);
- } while (!(sub_menu->entries[i++].menu_flags & wimp_MENU_LAST));
- } else {
- ro_gui_wimp_event_register_submenu((wimp_w)menu_entry->sub_menu);
- action = ro_gui_menu_find_action(current_menu, menu_entry);
- if (action != NO_ACTION)
- ro_gui_menu_prepare_action(current_menu_window,
- action, true);
- /* remove the close icon */
+ action, true);
+ }
+ }
+
+ /* If this is a dialogue box, remove the close and back icons. */
+
+ if (!(IS_MENU(menu_entry->sub_menu)))
ro_gui_wimp_update_window_furniture((wimp_w)menu_entry->sub_menu,
wimp_WINDOW_CLOSE_ICON | wimp_WINDOW_BACK_ICON, 0);
- }
+
/* open the sub-menu */
error = xwimp_create_sub_menu(menu_entry->sub_menu,
warning->pos.x, warning->pos.y);
@@ -829,64 +762,44 @@
*/
void ro_gui_menu_refresh_toolbar(struct toolbar *toolbar)
{
+// struct treeview_window *treeview_window;
assert(toolbar);
toolbar->reformat_buttons = true;
ro_gui_theme_process_toolbar(toolbar, -1);
if (toolbar->type == THEME_BROWSER_TOOLBAR) {
- gui_window_update_extent(ro_gui_window_lookup(current_menu_window));
- } else if (toolbar->type == THEME_HOTLIST_TOOLBAR) {
- tree_resized(hotlist_tree);
- xwimp_force_redraw((wimp_w)hotlist_tree->handle,
- 0,-16384, 16384, 16384);
- } else if (toolbar->type == THEME_HISTORY_TOOLBAR) {
- tree_resized(global_history_tree);
- xwimp_force_redraw((wimp_w)global_history_tree->handle,
- 0,-16384, 16384, 16384);
- } else if (toolbar->type == THEME_COOKIES_TOOLBAR) {
- tree_resized(cookies_tree);
- xwimp_force_redraw((wimp_w)cookies_tree->handle,
- 0,-16384, 16384, 16384);
+ gui_window_update_extent(ro_gui_window_lookup(
+ current_menu_window));
+// } else if (toolbar->type == THEME_HOTLIST_TOOLBAR) {
+// treeview_window = ro_gui_hotlist_get();
+// /* TODO: FIX THIS */
+// /* tree_resized(treeview_window->tree); */
+// xwimp_force_redraw(treeview_window->window,
+// 0,-16384, 16384, 16384);
+// } else if (toolbar->type == THEME_HISTORY_TOOLBAR) {
+// treeview_window = ro_gui_global_history_get();
+// /* TODO: FIX THIS */
+// /* tree_resized(treeview_window->tree); */
+// xwimp_force_redraw(treeview_window->window,
+// 0,-16384, 16384, 16384);
+// } else if (toolbar->type == THEME_COOKIES_TOOLBAR) {
+// treeview_window = ro_gui_cookies_get();
+// /* TODO: FIX THIS */
+// /* tree_resized(treeview_window->tree); */
+// xwimp_force_redraw(treeview_window->window,
+// 0,-16384, 16384, 16384);
}
}
/**
- * Builds the URL suggestion menu
- */
-bool ro_gui_menu_prepare_url_suggest(void) {
- char **suggest_text;
- int suggestions;
- int i;
-
- suggest_text = global_history_get_recent(&suggestions);
- if (suggestions < 1)
- return false;
-
- for (i = 0; i < suggestions; i++) {
- url_suggest_menu->entries[i].menu_flags = 0;
- url_suggest_menu->entries[i].data.indirected_text.text =
- suggest_text[i];
- url_suggest_menu->entries[i].data.indirected_text.size =
- strlen(suggest_text[i]) + 1;
- }
-
- url_suggest_menu->entries[0].menu_flags |= wimp_MENU_TITLE_INDIRECTED;
- url_suggest_menu->entries[suggestions - 1].menu_flags |= wimp_MENU_LAST;
- return true;
-}
-
-
-/**
* Update navigate menu status and toolbar icons.
*
* /param gui the gui_window to update
*/
void ro_gui_prepare_navigate(struct gui_window *gui)
{
- int suggestions;
-
ro_gui_menu_prepare_action(gui->window, HOTLIST_SHOW, false);
ro_gui_menu_prepare_action(gui->window, BROWSER_NAVIGATE_STOP, false);
ro_gui_menu_prepare_action(gui->window, BROWSER_NAVIGATE_RELOAD_ALL,
@@ -902,9 +815,9 @@
ro_gui_menu_prepare_action(gui->window, BROWSER_FIND_TEXT, false);
if (gui->toolbar) {
- global_history_get_recent(&suggestions);
ro_gui_set_icon_shaded_state(gui->toolbar->toolbar_handle,
- ICON_TOOLBAR_SUGGEST, (suggestions <= 0));
+ ICON_TOOLBAR_SUGGEST,
+ !ro_gui_url_suggest_prepare_menu());
}
}
@@ -1122,8 +1035,10 @@
/**
* Creates a wimp_menu and adds it to the list to handle actions for.
*
- * \param menu the data to create the menu with
- * \return the menu created, or NULL on failure
+ * \param *menu The data to create the menu with
+ * \param *callbacks A callback table for the menu (NULL if to be
+ * handled in the 'old-fashined way' by menus.c).
+ * \return The menu created, or NULL on failure
*/
wimp_menu *ro_gui_menu_define_menu(const struct ns_menu *menu)
{
@@ -1475,13 +1390,12 @@
struct browser_window *bw = NULL;
hlcache_handle *h = NULL;
struct toolbar *t = NULL;
- struct tree *tree;
- struct node *node;
os_error *error;
char url[80];
- const struct url_data *data;
+ bool is_cookies, is_hotlist, is_global_history;
- ro_gui_menu_get_window_details(owner, &g, &bw, &h, &t, &tree);
+ ro_gui_menu_get_window_details(owner, &g, &bw, &h, &t,
+ &is_cookies, &is_hotlist, &is_global_history);
switch (action) {
@@ -1515,42 +1429,26 @@
windows_at_pointer);
return true;
case HISTORY_SHOW_GLOBAL:
- ro_gui_tree_show(global_history_tree);
+ ro_gui_global_history_open();
return true;
/* hotlist actions */
case HOTLIST_ADD_URL:
- if ((!hotlist_tree) || (!h) || (!content_get_url(h)))
+ if (h == NULL || content_get_url(h) == NULL)
return false;
- data = urldb_get_url_data(content_get_url(h));
- if (data) {
- node = tree_create_URL_node(hotlist_tree->root,
- content_get_url(h),
- data, data->title);
- if (node) {
- tree_redraw_area(hotlist_tree,
- node->box.x - NODE_INSTEP, 0,
- NODE_INSTEP, 16384);
- tree_handle_node_changed(hotlist_tree,
- node, false, true);
- ro_gui_tree_scroll_visible(hotlist_tree,
- &node->data);
- ro_gui_hotlist_save();
- }
- }
+ hotlist_add_page(content_get_url(h));
return true;
case HOTLIST_SHOW:
- ro_gui_tree_show(hotlist_tree);
+ ro_gui_hotlist_open();
return true;
/* cookies actions */
case COOKIES_SHOW:
- ro_gui_tree_show(cookies_tree);
+ ro_gui_cookies_open();
return true;
case COOKIES_DELETE:
- if (cookies_tree->root->child)
- tree_delete_node(cookies_tree, cookies_tree->root->child, true);
+ cookies_delete_all();
return true;
/* page actions */
@@ -1635,8 +1533,6 @@
if (!h)
return false;
/* Fall through */
- case HOTLIST_EXPORT:
- case HISTORY_EXPORT:
ro_gui_menu_prepare_action(owner, action, true);
ro_gui_dialog_open_persistent(owner, dialog_saveas,
windows_at_pointer);
@@ -1788,61 +1684,6 @@
ro_gui_save_options();
return true;
- /* tree actions */
- case TREE_NEW_FOLDER:
- ro_gui_menu_prepare_action(owner, action, true);
- ro_gui_dialog_open_persistent((wimp_w)tree->handle,
- dialog_folder, windows_at_pointer);
- return true;
- case TREE_NEW_LINK:
- ro_gui_menu_prepare_action(owner, action, true);
- ro_gui_dialog_open_persistent((wimp_w)tree->handle,
- dialog_entry, windows_at_pointer);
- return true;
- case TREE_EXPAND_ALL:
- case TREE_EXPAND_FOLDERS:
- case TREE_EXPAND_LINKS:
- tree_handle_expansion(tree, tree->root, true,
- (action != TREE_EXPAND_LINKS),
- (action != TREE_EXPAND_FOLDERS));
- return true;
- case TREE_COLLAPSE_ALL:
- case TREE_COLLAPSE_FOLDERS:
- case TREE_COLLAPSE_LINKS:
- tree_handle_expansion(tree, tree->root, false,
- (action != TREE_COLLAPSE_LINKS),
- (action != TREE_COLLAPSE_FOLDERS));
- return true;
- case TREE_SELECTION_EDIT:
- return true;
- case TREE_SELECTION_LAUNCH:
- ro_gui_tree_launch_selected(tree);
- return true;
- case TREE_SELECTION_DELETE:
- ro_gui_tree_stop_edit(tree);
- tree_delete_selected_nodes(tree, tree->root);
- if (tree == hotlist_tree)
- ro_gui_hotlist_save();
- ro_gui_menu_prepare_action(owner, TREE_CLEAR_SELECTION, true);
- ro_gui_menu_prepare_action(owner, TREE_SELECTION, true);
- return true;
- case TREE_SELECT_ALL:
- ro_gui_tree_stop_edit(tree);
- if (tree->root->child) {
- tree->temp_selection = NULL;
- tree_set_node_selected(tree, tree->root, true);
- }
- ro_gui_menu_prepare_action(owner, TREE_CLEAR_SELECTION, true);
- ro_gui_menu_prepare_action(owner, TREE_SELECTION, true);
- return true;
- case TREE_CLEAR_SELECTION:
- tree->temp_selection = NULL;
- ro_gui_tree_stop_edit(tree);
- tree_set_node_selected(tree, tree->root, false);
- ro_gui_menu_prepare_action(owner, TREE_CLEAR_SELECTION, true);
- ro_gui_menu_prepare_action(owner, TREE_SELECTION, true);
- return true;
-
/* toolbar actions */
case TOOLBAR_BUTTONS:
assert(t);
@@ -1895,21 +1736,20 @@
void ro_gui_menu_prepare_action(wimp_w owner, menu_action action,
bool windows)
{
- struct menu_definition_entry *entry;
struct gui_window *g;
struct browser_window *bw;
hlcache_handle *h;
struct toolbar *t;
- struct tree *tree;
- struct node *node;
bool result = false;
int checksum = 0;
os_error *error;
char *parent;
url_func_result res;
bool compare;
+ bool is_cookies, is_hotlist, is_global_history;
- ro_gui_menu_get_window_details(owner, &g, &bw, &h, &t, &tree);
+ ro_gui_menu_get_window_details(owner, &g, &bw, &h, &t,
+ &is_cookies, &is_hotlist, &is_global_history);
if (current_menu_open)
checksum = ro_gui_menu_get_checksum();
if (!h) {
@@ -1935,37 +1775,13 @@
!(h || history_back_available(bw->history) ||
history_forward_available(bw->history))));
break;
- case HISTORY_SHOW_GLOBAL:
- ro_gui_menu_set_entry_shaded(current_menu, action,
- !global_history_tree);
- break;
/* hotlist actions */
case HOTLIST_ADD_URL:
ro_gui_menu_set_entry_shaded(current_menu, action,
- (!h || !hotlist_tree));
+ h == NULL);
break;
- case HOTLIST_SHOW:
- ro_gui_menu_set_entry_shaded(current_menu, action,
- !hotlist_tree);
- if ((t) && (!t->editor) &&
- (t->type == THEME_BROWSER_TOOLBAR))
- ro_gui_set_icon_shaded_state(
- t->toolbar_handle,
- ICON_TOOLBAR_BOOKMARK,
- !hotlist_tree);
- break;
- /* cookies actions */
- case COOKIES_SHOW:
- ro_gui_menu_set_entry_shaded(current_menu, action,
- !cookies_tree);
- break;
- case COOKIES_DELETE:
- ro_gui_menu_set_entry_shaded(current_menu, action,
- !(cookies_tree && cookies_tree->root->child));
- break;
-
/* page actions */
case BROWSER_PAGE:
ro_gui_menu_set_entry_shaded(current_menu,
@@ -2003,7 +1819,8 @@
/* object actions */
case BROWSER_OBJECT:
ro_gui_menu_set_entry_shaded(current_menu, action,
- !current_menu_object && !current_menu_url);
+ !current_menu_object &&
+ !current_menu_url);
break;
case BROWSER_OBJECT_LINK:
@@ -2013,7 +1830,8 @@
case BROWSER_OBJECT_INFO:
if (windows && current_menu_object)
- ro_gui_menu_prepare_objectinfo(current_menu_object,
+ ro_gui_menu_prepare_objectinfo(
+ current_menu_object,
current_menu_url);
/* Fall through */
case BROWSER_OBJECT_RELOAD:
@@ -2024,7 +1842,8 @@
case BROWSER_OBJECT_PRINT:
/* not yet implemented */
- ro_gui_menu_set_entry_shaded(current_menu, action, true);
+ ro_gui_menu_set_entry_shaded(current_menu, action,
+ true);
break;
/* save actions (browser, hotlist, history) */
@@ -2032,7 +1851,8 @@
ro_gui_menu_set_entry_shaded(current_menu,
action, !current_menu_object);
if (windows && current_menu_object)
- ro_gui_save_prepare(GUI_SAVE_OBJECT_ORIG, current_menu_object,
+ ro_gui_save_prepare(GUI_SAVE_OBJECT_ORIG,
+ current_menu_object,
NULL, NULL, NULL);
break;
case BROWSER_OBJECT_EXPORT:
@@ -2047,41 +1867,41 @@
if (h) {
switch (content_get_type(h)) {
/* \todo - this classification should prob be done in content_() */
- /* bitmap types (Sprite export possible) */
+ /* bitmap types (Sprite export possible) */
#ifdef WITH_JPEG
- case CONTENT_JPEG:
+ case CONTENT_JPEG:
#endif
#ifdef WITH_MNG
- case CONTENT_JNG:
- case CONTENT_MNG:
+ case CONTENT_JNG:
+ case CONTENT_MNG:
#endif
#ifdef WITH_GIF
- case CONTENT_GIF:
+ case CONTENT_GIF:
#endif
#ifdef WITH_BMP
- case CONTENT_BMP:
- case CONTENT_ICO:
+ case CONTENT_BMP:
+ case CONTENT_ICO:
#endif
#if defined(WITH_MNG) || defined(WITH_PNG)
- case CONTENT_PNG:
+ case CONTENT_PNG:
#endif
#ifdef WITH_SPRITE
- case CONTENT_SPRITE:
+ case CONTENT_SPRITE:
#endif
- exp_sprite = true;
- break;
+ exp_sprite = true;
+ break;
- /* vector types (Draw export possible) */
+ /* vector types (Draw export possible) */
#if defined(WITH_NS_SVG) || defined(WITH_RSVG)
- case CONTENT_SVG:
+ case CONTENT_SVG:
#endif
#ifdef WITH_DRAW
- case CONTENT_DRAW:
+ case CONTENT_DRAW:
#endif
- exp_draw = true;
- break;
+ exp_draw = true;
+ break;
- default: break;
+ default: break;
}
}
@@ -2229,16 +2049,6 @@
content_get_url(h),
content_get_title(h));
break;
- case HOTLIST_EXPORT:
- if ((tree) && (windows))
- ro_gui_save_prepare(GUI_SAVE_HOTLIST_EXPORT_HTML,
- NULL, NULL, NULL, NULL);
- break;
- case HISTORY_EXPORT:
- if ((tree) && (windows))
- ro_gui_save_prepare(GUI_SAVE_HISTORY_EXPORT_HTML,
- NULL, NULL, NULL, NULL);
- break;
/* navigation actions */
case BROWSER_NAVIGATE_BACK:
@@ -2379,83 +2189,8 @@
break;
/* tree actions */
- case TREE_NEW_FOLDER:
- ro_gui_hotlist_prepare_folder_dialog(NULL);
- break;
- case TREE_NEW_LINK:
- ro_gui_hotlist_prepare_entry_dialog(NULL);
- break;
- case TREE_EXPAND_ALL:
- case TREE_EXPAND_FOLDERS:
- case TREE_EXPAND_LINKS:
- case TREE_COLLAPSE_ALL:
- case TREE_COLLAPSE_FOLDERS:
- case TREE_COLLAPSE_LINKS:
- if ((tree) && (tree->root)) {
- ro_gui_menu_set_entry_shaded(current_menu,
- action, !tree->root->child);
-
- if ((t) && (!t->editor) && (t->type !=
- THEME_BROWSER_TOOLBAR)) {
- ro_gui_set_icon_shaded_state(
- t->toolbar_handle,
- ICON_TOOLBAR_EXPAND,
- !tree->root->child);
- ro_gui_set_icon_shaded_state(
- t->toolbar_handle,
- ICON_TOOLBAR_OPEN,
- !tree->root->child);
- }
- }
- break;
case TREE_SELECTION:
- if ((!tree) || (!tree->root))
- break;
- if (tree->root->child)
- result = tree_has_selection(tree->root->child);
- ro_gui_menu_set_entry_shaded(current_menu,
- action, !result);
- if ((t) && (!t->editor) &&
- (t->type != THEME_BROWSER_TOOLBAR)) {
- ro_gui_set_icon_shaded_state(
- t->toolbar_handle,
- ICON_TOOLBAR_DELETE, !result);
- ro_gui_set_icon_shaded_state(
- t->toolbar_handle,
- ICON_TOOLBAR_LAUNCH, !result);
- }
break;
- case TREE_SELECTION_EDIT:
- node = tree_get_selected_node(tree->root);
- entry = ro_gui_menu_find_entry(current_menu, action);
- if ((!node) || (!entry))
- break;
- if (node->folder) {
- entry->menu_entry->sub_menu =
- (wimp_menu *)dialog_folder;
- if (windows)
- ro_gui_hotlist_prepare_folder_dialog(node);
- } else {
- entry->menu_entry->sub_menu =
- (wimp_menu *)dialog_entry;
- if (windows)
- ro_gui_hotlist_prepare_entry_dialog(node);
- }
- break;
- case TREE_SELECTION_LAUNCH:
- case TREE_SELECTION_DELETE:
- case TREE_CLEAR_SELECTION:
- if ((!tree) || (!tree->root))
- break;
- if (tree->root->child)
- result = tree_has_selection(tree->root->child);
- ro_gui_menu_set_entry_shaded(current_menu,
- action, !result);
- break;
- case TREE_SELECT_ALL:
- ro_gui_menu_set_entry_shaded(current_menu, action,
- !tree->root->child);
- break;
/* toolbar actions */
case TOOLBAR_BUTTONS:
@@ -2509,31 +2244,35 @@
*/
void ro_gui_menu_get_window_details(wimp_w w, struct gui_window **g,
struct browser_window **bw, hlcache_handle **h,
- struct toolbar **toolbar, struct tree **tree)
+ struct toolbar **toolbar,
+ bool *is_cookies, bool *is_hotlist, bool *is_global_history)
{
+ *is_cookies = false;
+ *is_hotlist = false;
+ *is_global_history = false;
+
*g = ro_gui_window_lookup(w);
+
if (*g) {
*bw = (*g)->bw;
*toolbar = (*g)->toolbar;
if (*bw)
*h = (*bw)->current_content;
- *tree = NULL;
} else {
*bw = NULL;
*h = NULL;
- if ((hotlist_tree) && (w == (wimp_w)hotlist_tree->handle))
- *tree = hotlist_tree;
- else if ((global_history_tree) &&
- (w == (wimp_w)global_history_tree->handle))
- *tree = global_history_tree;
- else if ((cookies_tree) && (w == (wimp_w)cookies_tree->handle))
- *tree = cookies_tree;
- else
- *tree = NULL;
- if (*tree)
- *toolbar = (*tree)->toolbar;
- else
+ if (ro_gui_hotlist_check_window(w)) {
+ *is_hotlist = true;
+// *toolbar = treeview_window->toolbar;
+ } else if (ro_gui_global_history_check_window(w)) {
+ *is_global_history = true;
+// *toolbar = treeview_window->toolbar;
+ } else if (ro_gui_cookies_check_window(w)) {
+ *is_cookies = true;
+// *toolbar = treeview_window->toolbar;
+ } else {
*toolbar = NULL;
+ }
}
}
@@ -2595,6 +2334,7 @@
char *translated;
utf8_convert_ret err;
+
/* read current alphabet */
error = xosbyte1(osbyte_ALPHABET_NUMBER, 127, 0, &alphabet);
if (error) {
Index: riscos/help.c
===================================================================
--- riscos/help.c (revision 10834)
+++ riscos/help.c (working copy)
@@ -28,7 +28,10 @@
#include "oslib/taskmanager.h"
#include "oslib/wimp.h"
#include "desktop/tree.h"
+#include "riscos/cookies.h"
+#include "riscos/global_history.h"
#include "riscos/gui.h"
+#include "riscos/hotlist.h"
#include "riscos/help.h"
#include "riscos/menus.h"
#include "riscos/options.h"
@@ -100,7 +103,7 @@
os_error *error;
const char *auto_text;
int i;
-
+
/* check we aren't turned off */
if (!option_interactive_help)
return;
@@ -124,18 +127,17 @@
sprintf(message_token, "%s%i", auto_text, (int)icon);
else if (window == wimp_ICON_BAR)
sprintf(message_token, "HelpIconbar");
- else if ((hotlist_tree) && (window == (wimp_w)hotlist_tree->handle)) {
- i = ro_gui_tree_help(message_data->pos.x, message_data->pos.y);
+ else if (ro_gui_hotlist_check_window(message->data.data_xfer.w)) {
+ i = ro_treeview_get_help(message_data);
sprintf(message_token,
(i >= 0) ? "HelpTree%i" :"HelpHotlist%i", i);
- } else if ((global_history_tree) &&
- (window == (wimp_w)global_history_tree->handle)) {
- i = ro_gui_tree_help(message_data->pos.x, message_data->pos.y);
+ } else if (ro_gui_global_history_check_window(
+ message->data.data_xfer.w)) {
+ i = ro_treeview_get_help(message_data);
sprintf(message_token,
(i >= 0) ? "HelpTree%i" :"HelpGHistory%i", i);
- } else if ((cookies_tree) &&
- (window == (wimp_w)cookies_tree->handle)) {
- i = ro_gui_tree_help(message_data->pos.x, message_data->pos.y);
+ } else if (ro_gui_cookies_check_window(message->data.data_xfer.w)) {
+ i = ro_treeview_get_help(message_data);
sprintf(message_token,
(i >= 0) ? "HelpTree%i" :"HelpCookies%i", i);
} else if (ro_gui_window_lookup(window) != NULL)
@@ -173,11 +175,11 @@
sprintf(message_token, "HelpIconMenu");
else if (current_menu == browser_menu)
sprintf(message_token, "HelpBrowserMenu");
- else if (current_menu == hotlist_menu)
+ else if (ro_gui_hotlist_check_menu(current_menu))
sprintf(message_token, "HelpHotlistMenu");
- else if (current_menu == global_history_menu)
+ else if (ro_gui_global_history_check_menu(current_menu))
sprintf(message_token, "HelpGHistoryMenu");
- else if (current_menu == cookies_menu)
+ else if (ro_gui_cookies_check_menu(current_menu))
sprintf(message_token, "HelpCookiesMenu");
else
return;
@@ -323,7 +325,7 @@
char *help_start;
wimp_t task = 0;
os_error *error;
-
+
/* don't launch a second copy of anything */
if (ro_gui_interactive_help_available())
return;
Index: riscos/menus.h
===================================================================
--- riscos/menus.h (revision 10834)
+++ riscos/menus.h (working copy)
@@ -155,6 +155,20 @@
} menu_action;
+/* Menu entry structures for use when defining menus. */
+
+struct ns_menu_entry {
+ const char *text; /**< menu text (from messages) */
+ menu_action action; /**< associated action */
+ wimp_w *sub_window; /**< sub-window if any */
+};
+
+struct ns_menu {
+ const char *title;
+ struct ns_menu_entry entries[];
+};
+
+
void ro_gui_menu_init(void);
void ro_gui_menu_create(wimp_menu* menu, int x, int y, wimp_w w);
bool ro_gui_menu_handle_action(wimp_w owner, menu_action action,
@@ -171,4 +185,10 @@
const char *ro_gui_menu_find_menu_entry_key(wimp_menu *menu,
const char *translated);
+wimp_menu *ro_gui_menu_define_menu(const struct ns_menu *menu);
+void ro_gui_menu_set_entry_shaded(wimp_menu *menu, menu_action action,
+ bool shaded);
+void ro_gui_menu_set_entry_ticked(wimp_menu *menu, menu_action action,
+ bool ticked);
+
#endif
Conflicted files
Removed files
13 years
Re: Review: treeview-redux [6/7] -- Amiga frontend changes
by Chris Young
It seems to have unsurprisingly got very confused with the changes to
my menu code. I manually merged some of the changes back to trunk for
some reason or other - not exactly due to other changes - and then I
think I reverted some of these changes due to another problem. I'm
just as confused as SVN is, however I've managed to get the menu back
into the same state as it was for the old treeview branch - as far as
I know, as I can't actually test much (see below).
There are two main issues:
1. The hotlist fails to load/initialise. I've checked and I have the
initialisation steps. It seems to have read about one entry and then
given up, as (with the cancelling of a few errors) I ended up with a
somewhat truncated (no entries at all - only folder stubs) version of
my hotlist on disk (and no recent backup - my own fault, I should have
learnt from last time I played with this code). With no hotlist file
NetSurf generates a new one correctly. If other old hotlist files are
loading correctly I'll put this down to something iffy in mine and try
recreating it.
2. NetSurf fails to browse to any websites. This is a quite a serious
concern for a web browser :)
I've attached a log file showing NetSurf failing to load my homepage
and a couple of other sites. The key line seems to be:
utils/url.c url_normalize 182: url 'http://www.play.com' failed to match regex
NetSurf then passes it over to the search provider, which results in
exactly the same error again.
Maybe I'm missing something, as I would have expected this to have
been noticed already!
Chris
13 years
Review: treeview-redux [1/7] -- core changes
by John-Mark Bell
Precis:
This is part of the treeview-redux patchset.
It incorporates the changes on that branch today.
This patchset comprises 7 parts:
1. Core changes
2. Framebuffer frontend changes
3. GTK frontend changes
4. BeOS frontend changes
5. RISC OS frontend changes
6. Amiga frontend changes
7. Windows frontend changes
Added files
Index: Docs/09-treeview
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ Docs/09-treeview 2010-09-23 21:58:23.000000000 +0100
@@ -0,0 +1,68 @@
+Using the treeview gadget (together with core hotlist/history/cookies/sslcert)
+=========================
+
+Providing front end specific bits
+---------------------------------
+Most of the treeview logic is located in core code but there still are some
+functions that need implementing on the front end side. These include:
+
+- Functions marked as front end specific ones and listed at the end of
+ tree_url_node.h.
+- Functions in treeview_table located in tree.h
+
+Additionally the option_tree_icons_dir option should be set. It should be
+pointing at the directory containing the frontend specific icon set for the
+treeview.
+
+During GUI initialisation the following functions should be called:
+- cookies_initialise
+- history_global_initialise
+- hotlist_initialise
+- sslcert_init
+
+On GUI closure:
+- cookies_cleanup
+- history_global_cleanup
+- hotlist_cleanup
+- no function for sslcert here!
+
+The sslcert tree is created and deleted each time the dialog gets invoked. This
+is done with sslcert_create_tree and sslcert_cleanup. Make sure that closing the
+window with any other method will also perform the cleanup.
+
+The remaining functions in the header files of hotlist/history/cookies/sslcert
+have to be connected to the front end specific buttons and menu or tool bars.
+
+The front end is responsible for creating the windows and toolbars as well as
+empty core trees passed to the cookies/history/hotlist/sslcert initialisation
+functions. Use the *_get_tree_flags functions to obtain the flags with which the
+particular tree should be created.
+
+Using the treeview
+------------------
+
+1. Creating and modifying the tree structure
+
+- Create an empty tree with tree_create.
+- Create the necessary folder/leave nodes.
+- Fill the leave nodes with tree_create_node_element and assign content to the
+ elements with tree_update_node_element.
+- Use tree_link_node to connect the created nodes in the required structure.
+- With tree_set_redraw set the redraw flag on the tree to true, any further
+ changes will result in tree redraws. The flag can be set/unset multiple times.
+- Call tree_draw to draw the tree for the first time.
+
+2. Client -> Tree communication
+ To make the tree respond to mouse action, all such has to be passed
+ to tree_mouse_action and tree_drag_end. The mouse coordinates have to be given
+ with respect to the tree origin.
+
+3. Tree -> Client communication
+ Use tree_set_node_user_callback to provide a callback for any node related
+ events. At the moment it can be used for(default behaviour for a not handled
+ event in brackets):
+ - handling a node launch (no action)
+ - custom node element deletion (free text/bitmap)
+ - accepting/rejecting edited text (any text accepted)
+ - informing about edit end (no action)
+
Index: desktop/sslcert.c
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ desktop/sslcert.c 2010-09-23 21:58:31.000000000 +0100
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2009 Paul Blokus <paul_pl(a)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/>.
+ */
+
+/** \file
+ * SSL Certificate verification UI (implementation)
+ */
+
+#include "utils/config.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+#include "content/content.h"
+#include "content/fetch.h"
+#include "content/hlcache.h"
+#include "content/urldb.h"
+#include "desktop/browser.h"
+#include "desktop/sslcert.h"
+#include "desktop/tree.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+
+#define TREE_ELEMENT_SSL_VERSION 0x01
+#define TREE_ELEMENT_SSL_VALID_FROM 0x02
+#define TREE_ELEMENT_SSL_VALID_TO 0x03
+#define TREE_ELEMENT_SSL_CERT_TYPE 0x04
+#define TREE_ELEMENT_SSL_SERIAL 0x05
+#define TREE_ELEMENT_SSL_ISSUER 0x06
+
+struct sslcert_session_data {
+ unsigned long num;
+ char *url;
+ struct tree *tree;
+ nserror (*cb)(bool proceed, void *pw);
+ void *cbpw;
+};
+
+static struct node *sslcert_create_node(const struct ssl_cert_info *cert);
+static node_callback_resp sslcert_node_callback(void *user_data,
+ struct node_msg_data *msg_data);
+static void sslcert_clanup_session(struct sslcert_session_data *session);
+
+
+static hlcache_handle *sslcert_icon;
+
+void sslcert_init(void)
+{
+ sslcert_icon = tree_load_icon(tree_content_icon_name);
+}
+
+
+/**
+ * Get flags with which the sslcert tree should be created;
+ *
+ * \return the flags
+ */
+unsigned int sslcert_get_tree_flags(void)
+{
+ return TREE_NO_DRAGS | TREE_NO_SELECT;
+}
+
+
+void sslcert_cleanup(void)
+{
+ return;
+}
+
+struct sslcert_session_data *sslcert_create_session_data(unsigned long num,
+ const char *url, nserror (*cb)(bool proceed, void *pw),
+ void *cbpw)
+{
+ struct sslcert_session_data *data;
+
+ data = malloc(sizeof(struct sslcert_session_data));
+ if (data == NULL) {
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ data->url = strdup(url);
+ if (data->url == NULL) {
+ free(data);
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ data->num = num;
+ data->cb = cb;
+ data->cbpw = cbpw;
+
+ return data;
+}
+
+bool sslcert_load_tree(struct tree *tree, const struct ssl_cert_info *certs,
+ struct sslcert_session_data *data)
+{
+ struct node *tree_root;
+ struct node *node;
+ long i;
+
+ assert(data != NULL && certs != NULL && tree != NULL);
+
+ tree_root = tree_get_root(tree);
+
+ for (i = 0; i < (long)data->num; i++) {
+ node = sslcert_create_node(&(certs[i]));
+ if (node == NULL)
+ return NULL;
+ tree_link_node(tree, tree_root, node, false);
+ }
+
+ data->tree = tree;
+
+ return tree;
+
+}
+
+struct node *sslcert_create_node(const struct ssl_cert_info *cert)
+{
+ struct node *node;
+ struct node_element *element;
+ char buffer[356];
+ char *text;
+
+
+ snprintf(buffer, 356, messages_get("Subject"), cert->subject);
+ text = strdup(buffer);
+ if (text == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ node = tree_create_leaf_node(NULL, NULL, text,
+ false, false, false);
+ if (node == NULL) {
+ free(text);
+ return NULL;
+ }
+ tree_set_node_user_callback(node, sslcert_node_callback, NULL);
+
+ element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_SSL_ISSUER, false);
+ if (element != NULL) {
+ snprintf(buffer, 356, messages_get("Issuer"), cert->issuer);
+ text = strdup(buffer);
+ if (text == NULL) {
+ tree_delete_node(NULL, node, false);
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ tree_update_node_element(NULL, element, text, NULL);
+ }
+ element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_SSL_VERSION, false);
+ if (element != NULL) {
+ snprintf(buffer, 356, messages_get("Version"), cert->version);
+ text = strdup(buffer);
+ if (text == NULL) {
+ tree_delete_node(NULL, node, false);
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ tree_update_node_element(NULL, element, text, NULL);
+ }
+ element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_SSL_VALID_FROM, false);
+ if (element != NULL) {
+ snprintf(buffer, 356, messages_get("ValidFrom"),
+ cert->not_before);
+ text = strdup(buffer);
+ if (text == NULL) {
+ tree_delete_node(NULL, node, false);
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ tree_update_node_element(NULL, element, text, NULL);
+ }
+ element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_SSL_VALID_TO, false);
+ if (element != NULL) {
+ snprintf(buffer, 356, messages_get("ValidTo"), cert->not_after);
+ text = strdup(buffer);
+ if (text == NULL) {
+ tree_delete_node(NULL, node, false);
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ tree_update_node_element(NULL, element, text, NULL);
+ }
+ element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_SSL_CERT_TYPE, false);
+ if (element != NULL) {
+ snprintf(buffer, 356, messages_get("Type"), cert->cert_type);
+ text = strdup(buffer);
+ if (text == NULL) {
+ tree_delete_node(NULL, node, false);
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ tree_update_node_element(NULL, element, text, NULL);
+ }
+ element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_SSL_SERIAL, false);
+ if (element != NULL) {
+ snprintf(buffer, 356, messages_get("Serial"), cert->serial);
+ text = strdup(buffer);
+ if (text == NULL) {
+ tree_delete_node(NULL, node, false);
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ tree_update_node_element(NULL, element, text, NULL);
+ }
+
+ tree_set_node_icon(NULL, node, sslcert_icon);
+
+ return node;
+}
+
+
+node_callback_resp sslcert_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;
+}
+
+
+bool sslcert_reject(struct sslcert_session_data *session)
+{
+ session->cb(false, session->cbpw);
+ sslcert_clanup_session(session);
+ return true;
+}
+
+
+/**
+ * Handle acceptance of certificate
+ */
+bool sslcert_accept(struct sslcert_session_data *session)
+{
+ assert(session != NULL);
+
+ session->cb(true, session->cbpw);
+
+ sslcert_clanup_session(session);
+
+ return true;
+}
+
+void sslcert_clanup_session(struct sslcert_session_data *session)
+{
+ assert(session != NULL);
+
+ free(session->url);
+ free(session);
+}
Index: desktop/sslcert.h
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ desktop/sslcert.h 2010-09-23 21:58:32.000000000 +0100
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2009 Paul Blokus <paul_pl(a)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/>.
+ */
+
+
+#ifndef _NETSURF_DESKTOP_SSLCERT_H_
+#define _NETSURF_DESKTOP_SSLCERT_H_
+
+#include <stdbool.h>
+
+#include "desktop/tree.h"
+
+struct sslcert_session_data;
+
+void sslcert_init(void);
+unsigned int sslcert_get_tree_flags(void);
+void sslcert_cleanup(void);
+
+struct sslcert_session_data *sslcert_create_session_data(unsigned long num,
+ const char *url, nserror (*cb)(bool proceed, void *pw),
+ void *cbpw);
+bool sslcert_load_tree(struct tree *tree,
+ const struct ssl_cert_info *certs,
+ struct sslcert_session_data *data);
+
+bool sslcert_reject(struct sslcert_session_data *session);
+bool sslcert_accept(struct sslcert_session_data *session);
+
+
+#endif
Index: desktop/hotlist.c
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ desktop/hotlist.c 2010-09-23 21:58:32.000000000 +0100
@@ -0,0 +1,466 @@
+/*
+ * Copyright 2004, 2005 Richard Wilson <info(a)tinct.net>
+ * Copyright 2009 Paul Blokus <paul_pl(a)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 <ctype.h>
+#include <stdlib.h>
+
+#include "content/content.h"
+#include "content/hlcache.h"
+#include "content/urldb.h"
+#include "desktop/browser.h"
+#include "desktop/hotlist.h"
+#include "desktop/plotters.h"
+#include "desktop/tree.h"
+#include "desktop/tree_url_node.h"
+
+#include "utils/messages.h"
+#include "utils/utils.h"
+#include "utils/log.h"
+
+#define URL_CHUNK_LENGTH 512
+
+static struct tree *hotlist_tree;
+static struct node *hotlist_tree_root;
+
+static bool creating_node;
+static hlcache_handle *folder_icon;
+
+static const struct {
+ const char *url;
+ const char *msg_key;
+} default_entries[] = {
+ { "http://www.netsurf-browser.org/", "HotlistHomepage" },
+ { "http://www.netsurf-browser.org/downloads/riscos/testbuilds",
+ "HotlistTestBuild" },
+ { "http://www.netsurf-browser.org/documentation",
+ "HotlistDocumentation" },
+ { "http://sourceforge.net/tracker/?atid=464312&group_id=51719",
+ "HotlistBugTracker" },
+ { "http://sourceforge.net/tracker/?atid=464315&group_id=51719",
+ "HotlistFeatureRequest" }
+};
+#define ENTRIES_COUNT (sizeof(default_entries) / sizeof(default_entries[0]))
+
+
+static void hotlist_visited_internal(hlcache_handle *content,
+ struct node *node);
+static node_callback_resp hotlist_node_callback(void *user_data,
+ struct node_msg_data *msg_data);
+
+bool hotlist_initialise(struct tree *tree, const char *hotlist_path)
+{
+ FILE *fp = NULL;
+ struct node *node;
+ const struct url_data *url_data;
+ char *name;
+
+ /* Either load or create a hotlist */
+
+ creating_node = false;
+
+ folder_icon = tree_load_icon(tree_directory_icon_name);
+
+ tree_url_node_init();
+
+ if (tree == NULL)
+ return false;
+
+ hotlist_tree = tree;
+ hotlist_tree_root = tree_get_root(hotlist_tree);
+
+ if (hotlist_path != NULL)
+ fp = fopen(hotlist_path, "r");
+ if (fp == NULL) {
+ int i;
+
+ name = strdup("NetSurf");
+ if (name == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ node = tree_create_folder_node(hotlist_tree, hotlist_tree_root,
+ name, true, false, false);
+
+ if (node == NULL) {
+ free(name);
+ return false;
+ }
+ /* 1 indicates this is a folder */
+ tree_set_node_user_callback(node, hotlist_node_callback, NULL);
+ tree_set_node_icon(hotlist_tree, node, folder_icon);
+
+ for (i = 0; i != ENTRIES_COUNT; i++) {
+ url_data = urldb_get_url_data(default_entries[i].url);
+ if (url_data == NULL) {
+ urldb_add_url(default_entries[i].url);
+ urldb_set_url_persistence(
+ default_entries[i].url,
+ true);
+ url_data = urldb_get_url_data(
+ default_entries[i].url);
+ }
+ if (url_data != NULL) {
+ tree_create_URL_node(hotlist_tree, node,
+ default_entries[i].url,
+ messages_get(
+ default_entries[i].msg_key),
+ hotlist_node_callback, NULL);
+ tree_update_URL_node(hotlist_tree, node,
+ default_entries[i].url,
+ url_data, false);
+ }
+ }
+ } else {
+ fclose(fp);
+ if (!tree_url_load(hotlist_path, hotlist_tree,
+ hotlist_node_callback, NULL))
+ return false;
+ }
+
+
+ return true;
+}
+
+
+/**
+ * Get flags with which the hotlist tree should be created;
+ *
+ * \return the flags
+ */
+unsigned int hotlist_get_tree_flags(void)
+{
+ return TREE_MOVABLE;
+}
+
+
+/**
+ * Deletes the global history tree and saves the hotlist.
+ * \param hotlist_path the path where the hotlist should be saved
+ */
+void hotlist_cleanup(const char *hotlist_path)
+{
+ hotlist_export(hotlist_path);
+}
+
+
+/**
+ * Informs the hotlist that some content has been visited
+ *
+ * \param content the content visited
+ */
+void hotlist_visited(hlcache_handle *content)
+{
+ if (hotlist_tree)
+ hotlist_visited_internal(content, tree_get_root(hotlist_tree));
+}
+
+
+/**
+ * Informs the hotlist that some content has been visited. Internal procedure.
+ *
+ * \param content the content visited
+ * \param node the node to update siblings and children of
+ */
+void hotlist_visited_internal(hlcache_handle *content, struct node *node)
+{
+ struct node *child;
+ const char *text;
+ const char *url;
+
+ if (content == NULL || content_get_url(content) == NULL ||
+ hotlist_tree == NULL)
+ return;
+
+ url = content_get_url(content);
+
+ for (; node; node = tree_node_get_next(node)) {
+ if (!tree_node_is_folder(node)) {
+ text = tree_url_node_get_url(node);
+ if (!strcmp(text, url))
+ tree_update_URL_node(hotlist_tree, node,
+ url, NULL, false);
+ }
+ child = tree_node_get_child(node);
+ if (child != NULL)
+ hotlist_visited_internal(content, child);
+ }
+}
+
+
+node_callback_resp hotlist_node_callback(void *user_data, struct node_msg_data *msg_data)
+{
+ struct node *node = msg_data->node;
+ const char *text;
+ char *norm_text;
+ bool folder = tree_node_is_folder(node);
+
+ switch (msg_data->msg) {
+ case NODE_ELEMENT_EDIT_FINISHED:
+ if (creating_node && !folder &&
+ msg_data->flag == TREE_ELEMENT_TITLE) {
+ tree_url_node_edit_url(hotlist_tree, node);
+ }
+ else
+ creating_node = false;
+ return NODE_CALLBACK_HANDLED;
+ case NODE_ELEMENT_EDIT_FINISHING:
+ if (creating_node && !folder)
+ return tree_url_node_callback(hotlist_tree,
+ msg_data);
+
+ if (folder) {
+ text = msg_data->data.text;
+ while (isspace(*text))
+ text++;
+ norm_text = strdup(text);
+ if (norm_text == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return NODE_CALLBACK_REJECT;
+ }
+ /* don't allow zero length entry text, return
+ false */
+ if (norm_text[0] == '\0') {
+ warn_user("NoNameError", 0);
+ msg_data->data.text = NULL;
+ return NODE_CALLBACK_CONTINUE;
+ }
+ msg_data->data.text = norm_text;
+ }
+ break;
+ case NODE_DELETE_ELEMENT_IMG:
+ return NODE_CALLBACK_HANDLED;
+ default:
+ if (!folder)
+ return tree_url_node_callback(hotlist_tree,
+ msg_data);
+ }
+
+ return NODE_CALLBACK_NOT_HANDLED;
+}
+
+
+
+/**
+ * Save the hotlist in a human-readable form under the given location.
+ *
+ * \param path the path where the hotlist will be saved
+ */
+bool hotlist_export(const char *path)
+{
+ return tree_url_save(hotlist_tree, path, "NetSurf hotlist");
+}
+
+/**
+ * Edit the node which is currently selected. Works only if one node is
+ * selected.
+ */
+void hotlist_edit_selected(void)
+{
+ struct node *node;
+ struct node_element *element;
+
+ node = tree_get_selected_node(hotlist_tree_root);
+
+ if (node != NULL) {
+ creating_node = true;
+ element = tree_node_find_element(node, TREE_ELEMENT_TITLE,
+ NULL);
+ tree_start_edit(hotlist_tree, element);
+ }
+}
+
+/**
+ * Delete nodes which are currently selected.
+ */
+void hotlist_delete_selected(void)
+{
+ tree_delete_selected_nodes(hotlist_tree,
+ hotlist_tree_root);
+}
+
+/**
+ * Select all nodes in the tree.
+ */
+void hotlist_select_all(void)
+{
+ tree_set_node_selected(hotlist_tree, hotlist_tree_root,
+ true, true);
+}
+
+/**
+ * Unselect all nodes.
+ */
+void hotlist_clear_selection(void)
+{
+ tree_set_node_selected(hotlist_tree, hotlist_tree_root,
+ true, false);
+}
+
+/**
+ * Expand grouping folders and history entries.
+ */
+void hotlist_expand_all(void)
+{
+ tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
+ true, true, true);
+}
+
+/**
+ * Expand grouping folders only.
+ */
+void hotlist_expand_directories(void)
+{
+ tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
+ true, true, false);
+}
+
+/**
+ * Expand history entries only.
+ */
+void hotlist_expand_addresses(void)
+{
+ tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
+ true, false, true);
+}
+
+/**
+ * Collapse grouping folders and history entries.
+ */
+void hotlist_collapse_all(void)
+{
+ tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
+ false, true, true);
+}
+
+/**
+ * Collapse grouping folders only.
+ */
+void hotlist_collapse_directories(void)
+{
+ tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
+ false, true, false);
+}
+
+/**
+ * Collapse history entries only.
+ */
+void hotlist_collapse_addresses(void)
+{
+ tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
+ false, false, true);
+}
+
+/**
+ * Add a folder node.
+ */
+void hotlist_add_folder(void)
+{
+ struct node *node;
+ struct node_element *element;
+ char *title = strdup("Untitled");
+
+ if (title == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return;
+ }
+ creating_node = true;
+ node = tree_create_folder_node(hotlist_tree, hotlist_tree_root, title,
+ true, false, false);
+ if (node == NULL) {
+ free(title);
+ return;
+ }
+ tree_set_node_user_callback(node, hotlist_node_callback, NULL);
+ tree_set_node_icon(hotlist_tree, node, folder_icon);
+ element = tree_node_find_element(node, TREE_ELEMENT_TITLE, NULL);
+ tree_start_edit(hotlist_tree, element);
+}
+
+/**
+ * Add an entry node.
+ */
+void hotlist_add_entry(void)
+{
+ struct node *node;
+ creating_node = true;
+ node = tree_create_URL_node(hotlist_tree, hotlist_tree_root, "Address",
+ "Untitled", hotlist_node_callback, NULL);
+
+ if (node == NULL)
+ return;
+ tree_set_node_user_callback(node, hotlist_node_callback, NULL);
+ tree_url_node_edit_title(hotlist_tree, node);
+}
+
+/**
+ * Adds the currently viewed page to the hotlist
+ */
+void hotlist_add_page(const char *url)
+{
+ const struct url_data *data;
+ struct node *node;
+
+ if (url == NULL)
+ return;
+ data = urldb_get_url_data(url);
+ if (data == NULL)
+ return;
+
+ node = tree_create_URL_node(hotlist_tree, hotlist_tree_root, url, NULL,
+ hotlist_node_callback, NULL);
+ tree_update_URL_node(hotlist_tree, node, url, data, false);
+}
+
+/**
+ * Adds the currently viewed page to the hotlist at the given cooridinates
+ * \param url url of the page
+ * \param x X cooridinate with respect to tree origin
+ * \param y Y cooridinate with respect to tree origin
+ */
+void hotlist_add_page_xy(const char *url, int x, int y)
+{
+ const struct url_data *data;
+ struct node *link, *node;
+ bool before;
+
+ data = urldb_get_url_data(url);
+ if (data == NULL) {
+ urldb_add_url(url);
+ urldb_set_url_persistence(url, true);
+ data = urldb_get_url_data(url);
+ }
+ if (data != NULL) {
+ link = tree_get_link_details(hotlist_tree, x, y,
+ &before);
+ node = tree_create_URL_node(NULL, NULL, url,
+ NULL, hotlist_node_callback, NULL);
+ tree_link_node(hotlist_tree, link, node, before);
+ }
+}
+
+/**
+ * Open the selected entries in seperate browser windows.
+ */
+void hotlist_launch_selected(void)
+{
+ tree_launch_selected(hotlist_tree);
+}
Index: desktop/history_global_core.c
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ desktop/history_global_core.c 2010-09-23 21:58:32.000000000 +0100
@@ -0,0 +1,474 @@
+/*
+ * Copyright 2005 Richard Wilson <info(a)tinct.net>
+ * Copyright 2009 Paul Blokus <paul_pl(a)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_init;
+
+static struct tree *global_history_tree;
+static struct node *global_history_tree_root;
+
+static hlcache_handle *folder_icon;
+
+static bool history_global_initialise_nodes(void);
+static bool history_global_initialise_node(const char *title,
+ time_t base, int days_back);
+static bool global_history_add_internal(const char *url,
+ const struct url_data *data);
+static struct node *history_global_find(const char *url);
+static node_callback_resp history_global_node_callback(void *user_data,
+ struct node_msg_data *msg_data);
+
+static const char *const weekdays [] =
+{
+ "Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday"
+};
+
+/**
+ * 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_init = true;
+ urldb_iterate_entries(global_history_add_internal);
+ global_history_init = 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;
+}
+
+
+/**
+ * Initialises the grouping nodes(Today, Yesterday etc.) for the global history
+ * tree.
+ *
+ * \return false on memory exhaustion, true otherwise
+ */
+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 a single grouping node for the global history tree.
+ *
+ * \return false on memory exhaustion, true otherwise
+ */
+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(weekdays[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;
+}
+
+/**
+ * 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)
+ return;
+
+ global_history_add_internal(url, data);
+}
+
+
+/**
+ * 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)
+ */
+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 && data);
+
+ 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)
+ 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_init) {
+ node = history_global_find(url);
+ if (node) {
+ 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;
+}
+
+
+/**
+ * Find an entry in the global history
+ *
+ * \param url The URL to find
+ * \return Pointer to node, or NULL if not found
+ */
+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;
+}
+
+
+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;
+}
+
+/* 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_url_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 = tree_get_redraw(global_history_tree);
+ if (redraw)
+ 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)
+ 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);
+}
Index: desktop/hotlist.h
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ desktop/hotlist.h 2010-09-23 21:58:32.000000000 +0100
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2004, 2005 Richard Wilson <info(a)tinct.net>
+ * Copyright 2009 Paul Blokus <paul_pl(a)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/>.
+ */
+
+
+
+/** \file
+ * Hotlist (interface).
+ */
+
+#ifndef _NETSURF_DESKTOP_HOTLIST_H_
+#define _NETSURF_DESKTOP_HOTLIST_H_
+
+#include <stdbool.h>
+
+#include "desktop/tree.h"
+
+bool hotlist_initialise(struct tree *tree, const char *hotlist_path);
+unsigned int hotlist_get_tree_flags(void);
+void hotlist_cleanup(const char *hotlist_path);
+
+bool hotlist_export(const char *path);
+void hotlist_edit_selected(void);
+void hotlist_delete_selected(void);
+void hotlist_select_all(void);
+void hotlist_clear_selection(void);
+void hotlist_expand_all(void);
+void hotlist_expand_directories(void);
+void hotlist_expand_addresses(void);
+void hotlist_collapse_all(void);
+void hotlist_collapse_directories(void);
+void hotlist_collapse_addresses(void);
+void hotlist_add_folder(void);
+void hotlist_add_entry(void);
+void hotlist_add_page(const char *url);
+void hotlist_add_page_xy(const char *url, int x, int y);
+void hotlist_launch_selected(void);
+
+#endif
Index: desktop/cookies.c
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ desktop/cookies.c 2010-09-23 21:58:32.000000000 +0100
@@ -0,0 +1,636 @@
+/*
+ * Copyright 2006 Richard Wilson <info(a)tinct.net>
+ * Copyright 2009 Paul Blokus <paul_pl(a)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/>.
+ */
+
+/** \file
+ * Cookies (implementation).
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "content/content.h"
+#include "content/hlcache.h"
+#include "content/urldb.h"
+#include "desktop/cookies.h"
+#include "desktop/options.h"
+#include "desktop/tree.h"
+#include "utils/messages.h"
+#include "utils/log.h"
+#include "utils/url.h"
+#include "utils/utils.h"
+
+#define TREE_ELEMENT_PERSISTENT 0x01
+#define TREE_ELEMENT_VERSION 0x02
+#define TREE_ELEMENT_SECURE 0x03
+#define TREE_ELEMENT_LAST_USED 0x04
+#define TREE_ELEMENT_EXPIRES 0x05
+#define TREE_ELEMENT_PATH 0x06
+#define TREE_ELEMENT_DOMAIN 0x07
+#define TREE_ELEMENT_COMMENT 0x08
+#define TREE_ELEMENT_VALUE 0x09
+
+
+void cookies_schedule_callback(void *data);
+static struct node *cookies_find(struct node *node, const char *url);
+static struct node *cookies_create_cookie_node(struct node *parent,
+ const struct cookie_data *data);
+bool cookies_update_cookie_node(struct node *node,
+ const struct cookie_data *data);
+static node_callback_resp cookies_node_callback(void *user_data,
+ struct node_msg_data *msg_data);
+
+static struct tree *cookies_tree;
+static struct node *cookies_tree_root;
+static bool user_delete;
+static hlcache_handle *folder_icon;
+static hlcache_handle *cookie_icon;
+
+
+/**
+ * Initialises cookies 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 cookies_initialise(struct tree *tree)
+{
+
+ folder_icon = tree_load_icon(tree_directory_icon_name);
+ cookie_icon = tree_load_icon(tree_content_icon_name);
+
+ if (tree == NULL)
+ return false;
+
+ /* Create an empty tree */
+ cookies_tree = tree;
+ cookies_tree_root = tree_get_root(cookies_tree);
+
+ user_delete = false;
+ urldb_iterate_cookies(cookies_update);
+ tree_set_node_expanded(cookies_tree, cookies_tree_root,
+ true, true, true);
+
+ return true;
+}
+
+
+/**
+ * Get flags with which the cookies tree should be created;
+ *
+ * \return the flags
+ */
+unsigned int cookies_get_tree_flags(void)
+{
+ return TREE_DELETE_EMPTY_DIRS;
+}
+
+
+/**
+ * Perform cookie updates and addition. The update is only scheduled here.
+ * The actual update is performed in the callback function.
+ *
+ * \param data Data of cookie being updated.
+ * \return true (for urldb_iterate_entries)
+ */
+bool cookies_update(const struct cookie_data *data)
+{
+
+ assert(data);
+ assert(!user_delete);
+
+ schedule_remove(cookies_schedule_callback, (void *)data);
+ schedule(100, cookies_schedule_callback, (void *)data);
+
+ return true;
+}
+
+
+/**
+ * Deletes a cookie.
+ *
+ * \param data Data of cookie being updated.
+ * \return true (for urldb_iterate_entries)
+ */
+void cookies_delete(const struct cookie_data *data)
+{
+
+ assert(data);
+
+ schedule_remove(cookies_schedule_callback, (void *)data);
+}
+
+
+/**
+ * Funtion called when scheduled event gets fired. Performs actual cookie
+ * update.
+ */
+void cookies_schedule_callback(void *scheduled_data)
+{
+ const struct cookie_data *data = scheduled_data;
+ struct node *node = NULL;
+ struct node *cookie_node = NULL;
+ char *domain_cp;
+
+ node = cookies_find(cookies_tree_root, data->domain);
+
+ if (node == NULL) {
+ domain_cp = strdup(data->domain);
+ if (domain_cp == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return;
+ }
+ node = tree_create_folder_node(cookies_tree,
+ cookies_tree_root, domain_cp,
+ false, false, false);
+ if (node != NULL) {
+ tree_set_node_user_callback(node, cookies_node_callback,
+ NULL);
+ tree_set_node_icon(cookies_tree, node, folder_icon);
+ }
+ }
+
+ if (node == NULL)
+ return;
+
+ cookie_node = cookies_find(node, data->name);
+ if (cookie_node == NULL)
+ cookies_create_cookie_node(node, data);
+ else
+ cookies_update_cookie_node(cookie_node, data);
+
+ return;
+}
+
+
+/**
+ * Free memory and release all other resources.
+ */
+void cookies_cleanup(void)
+{
+}
+
+
+/**
+ * Find an entry in the cookie tree
+ *
+ * \param node the node to check the children of
+ * \param title The title to find
+ * \return Pointer to node, or NULL if not found
+ */
+struct node *cookies_find(struct node *node, const char *title)
+{
+ struct node *search;
+ struct node_element *element;
+
+ for (search = tree_node_get_child(node); search;
+ search = tree_node_get_next(search)) {
+ element = tree_node_find_element(search, TREE_ELEMENT_TITLE,
+ NULL);
+ if (!strcmp(title, tree_node_element_get_text(element)))
+ return search;
+ }
+ return NULL;
+}
+
+
+/**
+ * Creates an empty tree entry for a cookie, and links it into the tree.
+ *
+ * All information is copied from the cookie_data, and as such can
+ * be edited and should be freed.
+ *
+ * \param parent the node to link to
+ * \param data the cookie data to use
+ * \return the node created, or NULL for failure
+ */
+struct node *cookies_create_cookie_node(struct node *parent,
+ const struct cookie_data *data)
+{
+ struct node *node;
+ char *name;
+
+ name = strdup(data->name);
+ if (name == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+
+ node = tree_create_leaf_node(cookies_tree, NULL, name,
+ false, false, false);
+ if (node == NULL) {
+ free(name);
+ return NULL;
+ }
+
+ tree_set_node_user_callback(node, cookies_node_callback, NULL);
+
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_PERSISTENT, false);
+
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_VERSION, false);
+
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_SECURE, false);
+
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_LAST_USED, false);
+
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_EXPIRES, false);
+
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_PATH, false);
+
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_DOMAIN, false);
+
+ if ((data->comment) && (strcmp(data->comment, "")))
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_COMMENT, false);
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_VALUE, false);
+ tree_set_node_icon(cookies_tree, node, cookie_icon);
+
+ if (!cookies_update_cookie_node(node, data))
+ {
+ tree_delete_node(NULL, node, false);
+ return NULL;
+ }
+
+ tree_link_node(cookies_tree, parent, node, false);
+ return node;
+}
+
+
+/**
+ * Updates a tree entry for a cookie.
+ *
+ * All information is copied from the cookie_data, and as such can
+ * be edited and should be freed.
+ *
+ * \param node the node to update
+ * \param data the cookie data to use
+ * \return true if node updated, or false for failure
+ */
+bool cookies_update_cookie_node(struct node *node,
+ const struct cookie_data *data)
+{
+ struct node_element *element;
+ char buffer[256];
+ char buffer2[16];
+ char *text;
+ const char *old_text;
+
+
+ element = tree_node_find_element(node, TREE_ELEMENT_VALUE, NULL);
+ if (element != NULL) {
+ snprintf(buffer, 256, messages_get("TreeValue"),
+ data->value ?
+ data->value : messages_get("TreeUnused"));
+ old_text = tree_node_element_get_text(element);
+ if (old_text == NULL || strcmp(old_text, buffer) != 0) {
+ text = strdup(buffer);
+ if (text == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ tree_update_node_element(cookies_tree, element, text,
+ NULL);
+ }
+ }
+ if ((data->comment) && (strcmp(data->comment, ""))) {
+ element = tree_node_find_element(node, TREE_ELEMENT_COMMENT,
+ element);
+ if (element != NULL) {
+ snprintf(buffer, 256, messages_get("TreeComment"),
+ data->comment);
+ old_text = tree_node_element_get_text(element);
+ if (old_text == NULL || strcmp(old_text, buffer) != 0) {
+ text = strdup(buffer);
+ if (text == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ tree_update_node_element(cookies_tree, element,
+ text, NULL);
+ }
+ }
+ }
+ element = tree_node_find_element(node, TREE_ELEMENT_DOMAIN, element);
+ if (element != NULL) {
+ snprintf(buffer, 256, messages_get("TreeDomain"), data->domain,
+ data->domain_from_set ?
+ messages_get("TreeHeaders") : "");
+ old_text = tree_node_element_get_text(element);
+ if (old_text == NULL || strcmp(old_text, buffer) != 0) {
+ text = strdup(buffer);
+ if (text == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ tree_update_node_element(cookies_tree, element, text,
+ NULL);
+ }
+ }
+ element = tree_node_find_element(node, TREE_ELEMENT_PATH, element);
+ if (element != NULL) {
+ snprintf(buffer, 256, messages_get("TreePath"), data->path,
+ data->path_from_set ?
+ messages_get("TreeHeaders") : "");
+ old_text = tree_node_element_get_text(element);
+ if (old_text == NULL || strcmp(old_text, buffer) != 0) {
+ text = strdup(buffer);
+ if (text == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ tree_update_node_element(cookies_tree, element, text,
+ NULL);
+ }
+ }
+ element = tree_node_find_element(node, TREE_ELEMENT_EXPIRES, element);
+ if (element != NULL) {
+ snprintf(buffer, 256, messages_get("TreeExpires"),
+ (data->expires > 0)
+ ? (data->expires == 1)
+ ? messages_get("TreeSession")
+ : ctime(&data->expires)
+ : messages_get("TreeUnknown"));
+ if (data->expires > 0 && data->expires != 1)
+ buffer[strlen(buffer) - 1] = '\0';
+ old_text = tree_node_element_get_text(element);
+ if (old_text == NULL || strcmp(old_text, buffer) != 0) {
+ text = strdup(buffer);
+ if (text == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ tree_update_node_element(cookies_tree, element, text,
+ NULL);
+ }
+ }
+ element = tree_node_find_element(node, TREE_ELEMENT_LAST_USED, element);
+ if (element != NULL) {
+ snprintf(buffer, 256, messages_get("TreeLastUsed"),
+ (data->last_used > 0) ?
+ ctime(&data->last_used) :
+ messages_get("TreeUnknown"));
+ if (data->last_used > 0)
+ buffer[strlen(buffer) - 1] = '\0';
+ old_text = tree_node_element_get_text(element);
+ if (old_text == NULL || strcmp(old_text, buffer) != 0) {
+ text = strdup(buffer);
+ if (text == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ tree_update_node_element(cookies_tree, element, text,
+ NULL);
+ }
+ }
+ element = tree_node_find_element(node, TREE_ELEMENT_SECURE, element);
+ if (element != NULL) {
+ snprintf(buffer, 256, messages_get("TreeSecure"),
+ data->secure ?
+ messages_get("Yes") : messages_get("No"));
+ old_text = tree_node_element_get_text(element);
+ if (old_text == NULL || strcmp(old_text, buffer) != 0) {
+ text = strdup(buffer);
+ if (text == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ tree_update_node_element(cookies_tree, element, text,
+ NULL);
+ }
+ }
+ element = tree_node_find_element(node, TREE_ELEMENT_VERSION, element);
+ if (element != NULL) {
+ snprintf(buffer2, 16, "TreeVersion%i", data->version);
+ snprintf(buffer, 256, messages_get("TreeVersion"),
+ messages_get(buffer2));
+ old_text = tree_node_element_get_text(element);
+ if (old_text == NULL || strcmp(old_text, buffer) != 0) {
+ text = strdup(buffer);
+ if (text == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ tree_update_node_element(cookies_tree, element, text,
+ NULL);
+ }
+ }
+ element = tree_node_find_element(node, TREE_ELEMENT_PERSISTENT,
+ element);
+ if (element != NULL) {
+ snprintf(buffer, 256, messages_get("TreePersistent"),
+ data->no_destroy ?
+ messages_get("Yes") : messages_get("No"));
+ old_text = tree_node_element_get_text(element);
+ if (old_text == NULL || strcmp(old_text, buffer) != 0) {
+ text = strdup(buffer);
+ if (text == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ tree_update_node_element(cookies_tree, element, text,
+ NULL);
+ }
+ }
+
+ return node;
+}
+
+
+/**
+ * Callback for all cookie tree nodes.
+ */
+node_callback_resp cookies_node_callback(void *user_data, struct node_msg_data *msg_data)
+{
+ struct node *node = msg_data->node;
+ struct node_element *domain, *path;
+ const char *domain_t, *path_t, *name_t;
+ char *space;
+ bool folder = tree_node_is_folder(node);
+
+ /* we don't remove any icons here */
+ if (msg_data->msg == NODE_DELETE_ELEMENT_IMG)
+ return NODE_CALLBACK_HANDLED;
+
+ /* let the tree handle events other than text data removal */
+ if (msg_data->msg != NODE_DELETE_ELEMENT_TXT)
+ return NODE_CALLBACK_NOT_HANDLED;
+
+ /* check if it's a domain folder */
+ if (folder)
+ return NODE_CALLBACK_NOT_HANDLED;
+
+ switch (msg_data->flag) {
+ case TREE_ELEMENT_TITLE:
+ if (!user_delete)
+ break;
+ /* get the rest of the cookie data */
+ domain = tree_node_find_element(node,
+ TREE_ELEMENT_DOMAIN, NULL);
+ path = tree_node_find_element(node, TREE_ELEMENT_PATH,
+ NULL);
+
+ if (domain != NULL && path != NULL) {
+ domain_t = tree_node_element_get_text(domain) +
+ strlen(messages_get(
+ "TreeDomain")) - 4;
+ space = strchr(domain_t, ' ');
+ if (space)
+ *space = '\0';
+ path_t = tree_node_element_get_text(path) +
+ strlen(messages_get("TreePath"))
+ - 4;
+ space = strchr(path_t, ' ');
+ if (space)
+ *space = '\0';
+ name_t = msg_data->data.text;
+ urldb_delete_cookie(domain_t, path_t, name_t);
+ }
+ break;
+ default:
+ break;
+ }
+
+ free(msg_data->data.text);
+
+ return NODE_CALLBACK_HANDLED;
+}
+
+
+/* Actions to be connected to front end specific toolbars */
+
+/**
+ * Delete nodes which are currently selected.
+ */
+void cookies_delete_selected(void)
+{
+ user_delete = true;
+ tree_delete_selected_nodes(cookies_tree, cookies_tree_root);
+ user_delete = false;
+}
+
+/**
+ * Delete all nodes.
+ */
+void cookies_delete_all(void)
+{
+ bool redraw = tree_get_redraw(cookies_tree);
+ if (redraw)
+ tree_set_redraw(cookies_tree, false);
+
+ user_delete = true;
+ tree_set_node_selected(cookies_tree, cookies_tree_root, true, true);
+ tree_delete_selected_nodes(cookies_tree, cookies_tree_root);
+ user_delete = false;
+
+ if (redraw)
+ tree_set_redraw(cookies_tree, true);
+}
+
+/**
+ * Select all nodes in the tree.
+ */
+void cookies_select_all(void)
+{
+ tree_set_node_selected(cookies_tree, cookies_tree_root, true, true);
+}
+
+/**
+ * Unselect all nodes.
+ */
+void cookies_clear_selection(void)
+{
+ tree_set_node_selected(cookies_tree, cookies_tree_root, true, false);
+}
+
+/**
+ * Expand both domain and cookie nodes.
+ */
+void cookies_expand_all(void)
+{
+ tree_set_node_expanded(cookies_tree, cookies_tree_root,
+ true, true, true);
+}
+
+/**
+ * Expand domain nodes only.
+ */
+void cookies_expand_domains(void)
+{
+ tree_set_node_expanded(cookies_tree, cookies_tree_root,
+ true, true, false);
+}
+
+/**
+ * Expand cookie nodes only.
+ */
+void cookies_expand_cookies(void)
+{
+ tree_set_node_expanded(cookies_tree, cookies_tree_root,
+ true, false, true);
+}
+
+/**
+ * Collapse both domain and cookie nodes.
+ */
+void cookies_collapse_all(void)
+{
+ tree_set_node_expanded(cookies_tree, cookies_tree_root,
+ false, true, true);
+}
+
+/**
+ * Collapse domain nodes only.
+ */
+void cookies_collapse_domains(void)
+{
+ tree_set_node_expanded(cookies_tree, cookies_tree_root,
+ false, true, false);
+}
+
+/**
+ * Collapse cookie nodes only.
+ */
+void cookies_collapse_cookies(void)
+{
+ tree_set_node_expanded(cookies_tree, cookies_tree_root,
+ false, false, true);
+}
Index: desktop/history_global_core.h
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ desktop/history_global_core.h 2010-09-23 21:58:32.000000000 +0100
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2005 Richard Wilson <info(a)tinct.net>
+ * Copyright 2009 Paul Blokus <paul_pl(a)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/>.
+ */
+
+#ifndef _NETSURF_DESKTOP_HISTORY_GLOBAL_H_
+#define _NETSURF_DESKTOP_HISTORY_GLOBAL_H_
+
+#include <stdbool.h>
+
+#include "desktop/tree.h"
+
+bool history_global_initialise(struct tree *tree);
+unsigned int history_global_get_tree_flags(void);
+void history_global_cleanup(void);
+
+bool history_global_export(const char *path);
+void history_global_delete_selected(void);
+void history_global_delete_all(void);
+void history_global_select_all(void);
+void history_global_clear_selection(void);
+void history_global_expand_all(void);
+void history_global_expand_directories(void);
+void history_global_expand_addresses(void);
+void history_global_collapse_all(void);
+void history_global_collapse_directories(void);
+void history_global_collapse_addresses(void);
+void history_global_launch_selected(void);
+
+#endif
Index: desktop/tree_url_node.c
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ desktop/tree_url_node.c 2010-09-23 21:58:32.000000000 +0100
@@ -0,0 +1,846 @@
+/*
+ * Copyright 2005 Richard Wilson <info(a)tinct.net>
+ * Copyright 2009 Paul Blokus <paul_pl(a)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/>.
+ */
+
+/** \file
+ * Creation of URL nodes with use of trees (implementation)
+ */
+
+
+#include <assert.h>
+#include <ctype.h>
+#include <libxml/HTMLparser.h>
+#include <libxml/HTMLtree.h>
+
+#include "content/content.h"
+#include "content/hlcache.h"
+#include "content/urldb.h"
+#include "desktop/browser.h"
+#include "desktop/options.h"
+#include "desktop/tree_url_node.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/url.h"
+#include "utils/utils.h"
+
+#define TREE_ELEMENT_URL 0x01
+#define TREE_ELEMENT_LAST_VISIT 0x02
+#define TREE_ELEMENT_VISITS 0x03
+#define TREE_ELEMENT_THUMBNAIL 0x04
+
+#define MAX_ICON_NAME_LEN 256
+
+static bool initialised = false;
+
+struct icon_entry {
+ content_type type;
+ hlcache_handle *icon;
+};
+
+struct icon_entry icon_table[] = {
+ {CONTENT_HTML, NULL},
+ {CONTENT_TEXTPLAIN, NULL},
+ {CONTENT_CSS, NULL},
+#if defined(WITH_MNG) || defined(WITH_PNG)
+ {CONTENT_PNG, NULL},
+#endif
+#ifdef WITH_MNG
+ {CONTENT_JNG, NULL},
+ {CONTENT_MNG, NULL},
+#endif
+#ifdef WITH_JPEG
+ {CONTENT_JPEG, NULL},
+#endif
+#ifdef WITH_GIF
+ {CONTENT_GIF, NULL},
+#endif
+#ifdef WITH_BMP
+ {CONTENT_BMP, NULL},
+ {CONTENT_ICO, NULL},
+#endif
+#ifdef WITH_SPRITE
+ {CONTENT_SPRITE, NULL},
+#endif
+#ifdef WITH_DRAW
+ {CONTENT_DRAW, NULL},
+#endif
+#ifdef WITH_ARTWORKS
+ {CONTENT_ARTWORKS, NULL},
+#endif
+#ifdef WITH_NS_SVG
+ {CONTENT_SVG, NULL},
+#endif
+ {CONTENT_UNKNOWN, NULL},
+
+ /* this serves as a sentinel */
+ {CONTENT_HTML, NULL}
+};
+
+static hlcache_handle *folder_icon;
+
+static void tree_url_load_directory(xmlNode *ul, struct tree *tree,
+ struct node *directory, tree_node_user_callback callback,
+ void *callback_data);
+static void tree_url_load_entry(xmlNode *li, struct tree *tree,
+ struct node *directory,
+ tree_node_user_callback callback, void *callback_data);
+static xmlNode *tree_url_find_xml_element(xmlNode *node, const char *name);
+static bool tree_url_save_directory(struct node *directory, xmlNode *node);
+static bool tree_url_save_entry(struct node *entry, xmlNode *node);
+
+void tree_url_node_init(void)
+{
+ struct icon_entry *entry;
+ char icon_name[MAX_ICON_NAME_LEN];
+
+ if (initialised || option_tree_icons_dir == NULL)
+ return;
+ initialised = true;
+
+ folder_icon = tree_load_icon(tree_directory_icon_name);
+
+ entry = icon_table;
+ do {
+
+ tree_icon_name_from_content_type(icon_name, entry->type);
+ entry->icon = tree_load_icon(icon_name);
+
+ ++entry;
+ } while (entry->type != CONTENT_HTML);
+
+}
+
+
+/**
+ * Creates a tree entry for a URL, and links it into the tree
+ *
+ * \param parent the node to link to
+ * \param url the URL (copied)
+ * \param data the URL data to use
+ * \param title the custom title to use
+ * \return the node created, or NULL for failure
+ */
+struct node *tree_create_URL_node(struct tree *tree, struct node *parent,
+ const char *url, const char *title,
+ tree_node_user_callback user_callback, void *callback_data)
+{
+ struct node *node;
+ struct node_element *element;
+ char *text_cp, *squashed;
+
+ squashed = squash_whitespace(title ? title : url);
+ text_cp = strdup(squashed);
+ if (text_cp == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ free(squashed);
+ node = tree_create_leaf_node(tree, parent, text_cp, true, false,
+ false);
+ if (node == NULL) {
+ free(text_cp);
+ return NULL;
+ }
+
+ if (user_callback != NULL)
+ tree_set_node_user_callback(node, user_callback,
+ callback_data);
+
+ tree_create_node_element(node, NODE_ELEMENT_BITMAP,
+ TREE_ELEMENT_THUMBNAIL, false);
+ tree_create_node_element(node, NODE_ELEMENT_TEXT, TREE_ELEMENT_VISITS,
+ false);
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_LAST_VISIT, false);
+ element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_URL, true);
+ if (element) {
+ text_cp = strdup(url);
+ if (text_cp == NULL) {
+ tree_delete_node(tree, node, false);
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ tree_update_node_element(tree, element, text_cp, NULL);
+ }
+
+ return node;
+}
+
+
+/**
+ * Creates a tree entry for a URL, and links it into the tree.
+ *
+ * All information is used directly from the url_data, and as such cannot be
+ * edited and should never be freed.
+ *
+ * \param parent the node to link to
+ * \param url the URL
+ * \param data the URL data to use
+ * \return the node created, or NULL for failure
+ */
+struct node *tree_create_URL_node_shared(struct tree *tree, struct node *parent,
+ const char *url, const struct url_data *data,
+ tree_node_user_callback user_callback, void *callback_data)
+ {
+ struct node *node;
+ struct node_element *element;
+ const char *title;
+
+ assert(url && data);
+
+ if (data->title)
+ title = data->title;
+ else
+ title = url;
+ node = tree_create_leaf_node(tree, parent, title, false, false, false);
+ if (!node)
+ return NULL;
+
+ if (user_callback != NULL)
+ tree_set_node_user_callback(node, user_callback,
+ callback_data);
+
+ tree_create_node_element(node, NODE_ELEMENT_BITMAP,
+ TREE_ELEMENT_THUMBNAIL, false);
+ tree_create_node_element(node, NODE_ELEMENT_TEXT, TREE_ELEMENT_VISITS,
+ false);
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_LAST_VISIT, false);
+ element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_URL, false);
+ if (element)
+ tree_update_node_element(tree, element, url, NULL);
+
+ tree_update_URL_node(tree, node, url, data, true);
+ return node;
+}
+
+/**
+ * Updates the node details for a URL node.
+ *
+ * \param node the node to update
+ */
+void tree_update_URL_node(struct tree *tree, struct node *node,
+ const char *url, const struct url_data *data, bool shared)
+{
+ struct node_element *element;
+ char buffer[256];
+ struct bitmap *bitmap = NULL;
+ struct icon_entry *entry;
+ char *text_cp;
+
+ assert(node);
+
+ element = tree_node_find_element(node, TREE_ELEMENT_URL, NULL);
+ if (element == NULL)
+ return;
+
+ if (data != NULL) {
+ if (data->title == NULL)
+ urldb_set_url_title(url, url);
+
+ if (data->title == NULL)
+ return;
+
+ element = tree_node_find_element(node, TREE_ELEMENT_TITLE,
+ NULL);
+ if (shared)
+ tree_update_node_element(tree, element, data->title,
+ NULL);
+ else {
+ text_cp = strdup(data->title);
+ if (text_cp == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return;
+ }
+ tree_update_node_element(tree, element, text_cp, NULL);
+ }
+ } else {
+ data = urldb_get_url_data(url);
+ if (data == NULL)
+ return;
+ }
+
+ entry = icon_table;
+ do {
+ if (entry->type == data->type) {
+ if (entry->icon != NULL)
+ tree_set_node_icon(tree, node, entry->icon);
+ break;
+ }
+ ++entry;
+ } while (entry->type != CONTENT_HTML);
+
+ element = tree_node_find_element(node, TREE_ELEMENT_LAST_VISIT,
+ element);
+ if (element != NULL) {
+ snprintf(buffer, 256, messages_get("TreeLast"),
+ (data->last_visit > 0) ?
+ ctime((time_t *)&data->last_visit) :
+ messages_get("TreeUnknown"));
+ if (data->last_visit > 0)
+ buffer[strlen(buffer) - 1] = '\0';
+ text_cp = strdup(buffer);
+ if (text_cp == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return;
+ }
+ tree_update_node_element(tree, element, text_cp, NULL);
+ }
+
+ element = tree_node_find_element(node, TREE_ELEMENT_VISITS, element);
+ if (element != NULL) {
+ snprintf(buffer, 256, messages_get("TreeVisits"),
+ data->visits);
+ text_cp = strdup(buffer);
+ if (text_cp == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return;
+ }
+ tree_update_node_element(tree, element, text_cp, NULL);
+ }
+
+ element = tree_node_find_element(node, TREE_ELEMENT_THUMBNAIL, element);
+ if (element != NULL) {
+ bitmap = urldb_get_thumbnail(url);
+
+ if (bitmap != NULL) {
+ tree_update_node_element(tree, element, NULL, bitmap);
+ }
+ }
+}
+
+
+const char *tree_url_node_get_title(struct node *node)
+{
+ struct node_element *element;
+ element = tree_node_find_element(node, TREE_ELEMENT_TITLE, NULL);
+ if (element == NULL)
+ return NULL;
+ return tree_node_element_get_text(element);
+}
+
+
+const char *tree_url_node_get_url(struct node *node)
+{
+ struct node_element *element;
+ element = tree_node_find_element(node, TREE_ELEMENT_URL, NULL);
+ if (element == NULL)
+ return NULL;
+ return tree_node_element_get_text(element);
+}
+
+void tree_url_node_edit_title(struct tree *tree, struct node *node)
+{
+ struct node_element *element;
+ element = tree_node_find_element(node, TREE_ELEMENT_TITLE, NULL);
+ tree_start_edit(tree, element);
+}
+
+void tree_url_node_edit_url(struct tree *tree, struct node *node)
+{
+ struct node_element *element;
+ element = tree_node_find_element(node, TREE_ELEMENT_URL, NULL);
+ tree_start_edit(tree, element);
+}
+
+node_callback_resp tree_url_node_callback(void *user_data,
+ struct node_msg_data *msg_data)
+{
+ struct tree *tree;
+ struct node_element *element;
+ url_func_result res;
+ const char *text;
+ char *norm_text, *escaped_text;
+ const struct url_data *data;
+
+ /* TODO: memory leaks on non-shared folder deletion */
+ switch (msg_data->msg) {
+ case NODE_DELETE_ELEMENT_TXT:
+ switch (msg_data->flag) {
+ /* only history is using non-editable url
+ * elements so only history deletion will run
+ * this code
+ */
+ case TREE_ELEMENT_URL:
+ /* reset URL characteristics */
+ urldb_reset_url_visit_data(
+ msg_data->data.text);
+ return NODE_CALLBACK_HANDLED;
+ case TREE_ELEMENT_TITLE:
+ return NODE_CALLBACK_HANDLED;
+ }
+ break;
+ case NODE_DELETE_ELEMENT_IMG:
+ if (msg_data->flag == TREE_ELEMENT_THUMBNAIL ||
+ msg_data->flag == TREE_ELEMENT_TITLE)
+ return NODE_CALLBACK_HANDLED;
+ break;
+ case NODE_LAUNCH:
+ element = tree_node_find_element(msg_data->node,
+ TREE_ELEMENT_URL, NULL);
+ if (element != NULL) {
+ text = tree_node_element_get_text(element);
+ browser_window_create(text, NULL, 0,
+ true, false);
+ return NODE_CALLBACK_HANDLED;
+ }
+ break;
+ case NODE_ELEMENT_EDIT_FINISHING:
+
+ text = msg_data->data.text;
+
+ if (msg_data->flag == TREE_ELEMENT_URL) {
+ res = url_escape(text, 0, false, NULL,
+ &escaped_text);
+ if (res == URL_FUNC_OK)
+ res = url_normalize(escaped_text,
+ &norm_text);
+ if (res != URL_FUNC_OK) {
+ if (res == URL_FUNC_FAILED) {
+ warn_user("NoURLError", 0);
+ return NODE_CALLBACK_CONTINUE;
+ }
+ else {
+ warn_user("NoMemory", 0);
+ return NODE_CALLBACK_REJECT;
+ }
+
+ }
+ msg_data->data.text = norm_text;
+
+ data = urldb_get_url_data(norm_text);
+ if (data == NULL) {
+ urldb_add_url(norm_text);
+ urldb_set_url_persistence(norm_text,
+ true);
+ data = urldb_get_url_data(norm_text);
+ if (data == NULL)
+ return NODE_CALLBACK_REJECT;
+ }
+ tree = user_data;
+ tree_update_URL_node(tree, msg_data->node,
+ norm_text, NULL, false);
+ }
+ else if (msg_data->flag == TREE_ELEMENT_TITLE) {
+ while (isspace(*text))
+ text++;
+ norm_text = strdup(text);
+ if (norm_text == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return NODE_CALLBACK_REJECT;
+ }
+ /* don't allow zero length entry text, return
+ false */
+ if (norm_text[0] == '\0') {
+ warn_user("NoNameError", 0);
+ msg_data->data.text = NULL;
+ return NODE_CALLBACK_CONTINUE;
+ }
+ msg_data->data.text = norm_text;
+ }
+
+ return NODE_CALLBACK_HANDLED;
+ default:
+ break;
+ }
+ return NODE_CALLBACK_NOT_HANDLED;
+}
+
+
+/**
+ * Loads an url tree from a specified file.
+ *
+ * \param filename name of file to read
+ * \param tree empty tree which data will be read into
+ * \return the file represented as a tree, or NULL on failure
+ */
+bool tree_url_load(const char *filename, struct tree *tree,
+ tree_node_user_callback callback, void *callback_data)
+{
+ xmlDoc *doc;
+ xmlNode *html, *body, *ul;
+ struct node *root;
+
+ doc = htmlParseFile(filename, "iso-8859-1");
+ if (doc == NULL) {
+ warn_user("TreeLoadError", messages_get("ParsingFail"));
+ return false;
+ }
+
+ html = tree_url_find_xml_element((xmlNode *) doc, "html");
+ body = tree_url_find_xml_element(html, "body");
+ ul = tree_url_find_xml_element(body, "ul");
+ if (ul == NULL) {
+ xmlFreeDoc(doc);
+ warn_user("TreeLoadError",
+ "(<html>...<body>...<ul> not found.)");
+ return false;
+ }
+
+ root = tree_get_root(tree);
+ tree_url_load_directory(ul, tree, root, callback, callback_data);
+ tree_set_node_expanded(tree, root, true, false, false);
+
+ xmlFreeDoc(doc);
+ return true;
+}
+
+
+/**
+ * Parse a directory represented as a ul.
+ *
+ * \param ul xmlNode for parsed ul
+ * \param directory directory to add this directory to
+ */
+void tree_url_load_directory(xmlNode *ul, struct tree *tree,
+ struct node *directory, tree_node_user_callback callback,
+ void *callback_data)
+{
+ char *title;
+ struct node *dir;
+ xmlNode *n;
+
+ assert(ul);
+ assert(directory);
+
+ for (n = ul->children; n; n = n->next) {
+ /* The ul may contain entries as a li, or directories as
+ * an h4 followed by a ul. Non-element nodes may be present
+ * (eg. text, comments), and are ignored. */
+
+ if (n->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (strcmp((const char *) n->name, "li") == 0) {
+ /* entry */
+ tree_url_load_entry(n, tree, directory, callback,
+ callback_data);
+
+ } else if (strcmp((const char *) n->name, "h4") == 0) {
+ /* directory */
+ title = (char *) xmlNodeGetContent(n);
+ if (!title) {
+ warn_user("TreeLoadError", "(Empty <h4> "
+ "or memory exhausted.)");
+ return;
+ }
+
+ for (n = n->next;
+ n && n->type != XML_ELEMENT_NODE;
+ n = n->next)
+ ;
+ if (!n || strcmp((const char *) n->name, "ul") != 0) {
+ /* next element isn't expected ul */
+ free(title);
+ warn_user("TreeLoadError", "(Expected "
+ "<ul> not present.)");
+ return;
+ }
+
+ dir = tree_create_folder_node(tree, directory, title,
+ true, false, false);
+ if (dir == NULL) {
+ free(title);
+ return;
+ }
+
+ if (callback != NULL)
+ tree_set_node_user_callback(dir, callback,
+ callback_data);
+
+ if (folder_icon != NULL)
+ tree_set_node_icon(tree, dir, folder_icon);
+
+ tree_url_load_directory(n, tree, dir, callback,
+ callback_data);
+ }
+ }
+}
+
+
+/**
+ * Parse an entry represented as a li.
+ *
+ * \param li xmlNode for parsed li
+ * \param directory directory to add this entry to
+ */
+void tree_url_load_entry(xmlNode *li, struct tree *tree,
+ struct node *directory, tree_node_user_callback callback,
+ void *callback_data)
+{
+ char *url = NULL, *url1 = NULL;
+ char *title = NULL;
+ struct node *entry;
+ xmlNode *n;
+ const struct url_data *data;
+ url_func_result res;
+
+ for (n = li->children; n; n = n->next) {
+ /* The li must contain an "a" element */
+ if (n->type == XML_ELEMENT_NODE &&
+ strcmp((const char *) n->name, "a") == 0) {
+ url1 = (char *) xmlGetProp(n, (const xmlChar *) "href");
+ title = (char *) xmlNodeGetContent(n);
+ }
+ }
+
+ if (!url1 || !title) {
+ warn_user("TreeLoadError", "(Missing <a> in <li> or "
+ "memory exhausted.)");
+ return;
+ }
+
+ /* We're loading external input.
+ * This may be garbage, so attempt to normalise
+ */
+ res = url_normalize(url1, &url);
+ if (res != URL_FUNC_OK) {
+ LOG(("Failed normalising '%s'", url1));
+
+ if (res == URL_FUNC_NOMEM)
+ warn_user("NoMemory", NULL);
+
+ xmlFree(url1);
+ xmlFree(title);
+
+ return;
+ }
+
+ /* No longer need this */
+ xmlFree(url1);
+
+ data = urldb_get_url_data(url);
+ if (data == NULL) {
+ /* No entry in database, so add one */
+ urldb_add_url(url);
+ /* now attempt to get url data */
+ data = urldb_get_url_data(url);
+ }
+ if (data == NULL) {
+ xmlFree(title);
+ free(url);
+
+ return;
+ }
+
+ /* Make this URL persistent */
+ urldb_set_url_persistence(url, true);
+
+ if (data->title == NULL)
+ urldb_set_url_title(url, title);
+
+ entry = tree_create_URL_node(tree, directory, url, title,
+ callback, callback_data);
+
+ if (entry == NULL) {
+ /** \todo why isn't this fatal? */
+ warn_user("NoMemory", 0);
+ }
+ else
+ tree_update_URL_node(tree, entry, url, data, false);
+
+
+ xmlFree(title);
+ free(url);
+}
+
+
+/**
+ * Search the children of an xmlNode for an element.
+ *
+ * \param node xmlNode to search children of, or 0
+ * \param name name of element to find
+ * \return first child of node which is an element and matches name, or
+ * 0 if not found or parameter node is 0
+ */
+xmlNode *tree_url_find_xml_element(xmlNode *node, const char *name)
+{
+ xmlNode *n;
+ if (!node)
+ return 0;
+ for (n = node->children;
+ n && !(n->type == XML_ELEMENT_NODE &&
+ strcmp((const char *) n->name, name) == 0);
+ n = n->next)
+ ;
+ return n;
+}
+
+
+
+/**
+ * Perform a save to a specified file in the form of a html page
+ *
+ * \param filename the file to save to
+ * \param page_title title of the page
+ */
+bool tree_url_save(struct tree *tree, const char *filename,
+ const char *page_title)
+{
+ int res;
+ xmlDoc *doc;
+ xmlNode *html, *head, *title, *body;
+
+ /* Unfortunately the Browse Hotlist format is invalid HTML,
+ * so this is a lie. */
+ doc = htmlNewDoc(
+ (const xmlChar *) "http://www.w3.org/TR/html4/strict.dtd",
+ (const xmlChar *) "-//W3C//DTD HTML 4.01//EN");
+ if (doc == NULL) {
+ warn_user("NoMemory", 0);
+ return false;
+ }
+
+ html = xmlNewNode(NULL, (const xmlChar *) "html");
+ if (html == NULL) {
+ warn_user("NoMemory", 0);
+ xmlFreeDoc(doc);
+ return false;
+ }
+ xmlDocSetRootElement(doc, html);
+
+ head = xmlNewChild(html, NULL, (const xmlChar *) "head", NULL);
+ if (head == NULL) {
+ warn_user("NoMemory", 0);
+ xmlFreeDoc(doc);
+ return false;
+ }
+
+ title = xmlNewTextChild(head, NULL, (const xmlChar *) "title",
+ (const xmlChar *) page_title);
+ if (title == NULL) {
+ warn_user("NoMemory", 0);
+ xmlFreeDoc(doc);
+ return false;
+ }
+
+ body = xmlNewChild(html, NULL, (const xmlChar *) "body", NULL);
+ if (body == NULL) {
+ warn_user("NoMemory", 0);
+ xmlFreeDoc(doc);
+ return false;
+ }
+
+ if (!tree_url_save_directory(tree_get_root(tree), body)) {
+ warn_user("NoMemory", 0);
+ xmlFreeDoc(doc);
+ return false;
+ }
+
+ doc->charset = XML_CHAR_ENCODING_UTF8;
+ res = htmlSaveFileEnc(filename, doc, "iso-8859-1");
+ if (res == -1) {
+ warn_user("HotlistSaveError", 0);
+ xmlFreeDoc(doc);
+ return false;
+ }
+
+ xmlFreeDoc(doc);
+ return true;
+}
+
+
+/**
+ * Add a directory to the HTML tree for saving.
+ *
+ * \param directory hotlist directory to add
+ * \param node node to add ul to
+ * \return true on success, false on memory exhaustion
+ */
+bool tree_url_save_directory(struct node *directory, xmlNode *node)
+{
+ struct node *child;
+ xmlNode *ul, *h4;
+ const char *text;
+
+ ul = xmlNewChild(node, NULL, (const xmlChar *) "ul", NULL);
+ if (!ul)
+ return false;
+
+ for (child = tree_node_get_child(directory); child;
+ child = tree_node_get_next(child)) {
+ if (!tree_node_is_folder(child)) {
+ /* entry */
+ if (!tree_url_save_entry(child, ul))
+ return false;
+ } else {
+ /* directory */
+ /* invalid HTML */
+
+ text = tree_url_node_get_title(child);
+ if (text == NULL)
+ return false;
+
+ h4 = xmlNewTextChild(ul, NULL,
+ (const xmlChar *) "h4",
+ (const xmlChar *) text);
+ if (!h4)
+ return false;
+
+ if (!tree_url_save_directory(child, ul))
+ return false;
+ } }
+
+ return true;
+}
+
+
+/**
+ * Add an entry to the HTML tree for saving.
+ *
+ * The node must contain a sequence of node_elements in the following order:
+ *
+ * \param entry hotlist entry to add
+ * \param node node to add li to
+ * \return true on success, false on memory exhaustion
+ */
+bool tree_url_save_entry(struct node *entry, xmlNode *node)
+{
+ xmlNode *li, *a;
+ xmlAttr *href;
+ const char *text;
+
+ li = xmlNewChild(node, NULL, (const xmlChar *) "li", NULL);
+ if (!li)
+ return false;
+
+
+ text = tree_url_node_get_title(entry);
+ if (text == NULL)
+ return false;
+ a = xmlNewTextChild(li, NULL, (const xmlChar *) "a",
+ (const xmlChar *) text);
+ if (!a)
+ return false;
+
+ text = tree_url_node_get_url(entry);
+ if (text == NULL)
+ return false;
+ href = xmlNewProp(a, (const xmlChar *) "href", (const xmlChar *) text);
+ if (!href)
+ return false;
+ return true;
+}
Index: desktop/tree_url_node.h
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ desktop/tree_url_node.h 2010-09-23 21:58:33.000000000 +0100
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2005 Richard Wilson <info(a)tinct.net>
+ * Copyright 2009 Paul Blokus <paul_pl(a)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/>.
+ */
+
+/** \file
+ * Creation of URL nodes with use of trees public API
+ */
+
+#ifndef _NETSURF_DESKTOP_TREE_URL_NODE_H_
+#define _NETSURF_DESKTOP_TREE_URL_NODE_H_
+
+
+#include "desktop/tree.h"
+
+void tree_url_node_init(void);
+struct node *tree_create_URL_node(struct tree *tree,
+ struct node *parent, const char *url, const char *title,
+ tree_node_user_callback, void *callback_data);
+struct node *tree_create_URL_node_shared(struct tree *tree,
+ struct node *parent, const char *url,
+ const struct url_data *data,
+ tree_node_user_callback, void *callback_data);
+void tree_update_URL_node(struct tree *tree,struct node *node,
+ const char *url, const struct url_data *data, bool shared);
+const char *tree_url_node_get_title(struct node *node);
+const char *tree_url_node_get_url(struct node *node);
+void tree_url_node_edit_title(struct tree *tree, struct node *node);
+void tree_url_node_edit_url(struct tree *tree, struct node *node);
+
+node_callback_resp tree_url_node_callback(void *user_data,
+ struct node_msg_data *msg_data);
+
+bool tree_url_load(const char *filename, struct tree *tree,
+ tree_node_user_callback, void *callback_data);
+bool tree_url_save(struct tree *tree, const char *filename,
+ const char *page_title);
+
+/* front end specific */
+void tree_icon_name_from_content_type(char *buffer, content_type type);
+
+#endif
Changed files
!NetSurf/Resources/de/Messages | 10
!NetSurf/Resources/en/Messages | 29
!NetSurf/Resources/fr/Messages | 10
!NetSurf/Resources/it/Messages | 10
!NetSurf/Resources/nl/Messages | 10
Makefile.sources | 27
content/urldb.c | 49
content/urldb.h | 3
desktop/browser.c | 1
desktop/cookies.h | 19
desktop/options.c | 363 ----
desktop/options.h | 5
desktop/tree.c | 3072 ++++++++++++++++++++++++++++-------------
desktop/tree.h | 262 +--
14 files changed, 2424 insertions(+), 1446 deletions(-)
Index: !NetSurf/Resources/de/Messages
===================================================================
--- !NetSurf/Resources/de/Messages (revision 10834)
+++ !NetSurf/Resources/de/Messages (working copy)
@@ -189,6 +189,8 @@
New:Neu
Expand:Expandieren
Collapse:Zusammenfalten
+Tree:Tree
+TreeExport:Export...
# New hotlist entry menu
#
@@ -200,6 +202,7 @@
All:Alles
Folders:Verzeichnisse
Links:Einträge
+Domains:Domains
# Other menus
#
@@ -373,6 +376,13 @@
Date1Week:vorige Woche
Date2Week:vor 2 Wochen
Date3Week:vor 3 Wochen
+Sunday:Sunday
+Monday:Monday
+Tuesday:Tuesday
+Wednesday:Wednesday
+Thursday:Thursday
+Friday:Friday
+Saturday:Saturday
# Download user interface tokens
Index: !NetSurf/Resources/en/Messages
===================================================================
--- !NetSurf/Resources/en/Messages (revision 10834)
+++ !NetSurf/Resources/en/Messages (working copy)
@@ -189,6 +189,8 @@
New:New
Expand:Expand
Collapse:Collapse
+Tree:Tree
+TreeExport:Export...
# New hotlist entry menu
#
@@ -200,6 +202,7 @@
All:All
Folders:Directories
Links:Addresses
+Domains:Domains
# Other menus
#
@@ -332,6 +335,7 @@
TreeLaunch:Visit URL
TreeDelete:Delete
+
# Tree export
#
TreeHotlist:NetSurf hotlist
@@ -374,6 +378,13 @@
Date1Week:Last week
Date2Week:2 weeks ago
Date3Week:3 weeks ago
+Sunday:Sunday
+Monday:Monday
+Tuesday:Tuesday
+Wednesday:Wednesday
+Thursday:Thursday
+Friday:Friday
+Saturday:Saturday
# Download user interface tokens
@@ -534,6 +545,8 @@
gtkAddBookMarks:_Add to Bookmarks…
gtkShowBookMarks:_Show Bookmarks…
gtkShowBookMarksAccel:F6
+gtkShowCookies:Show _Cookies…
+gtkShowCookiesAccel:F9
gtkOpenLocation:_Open Location…
gtkOpenLocationAccel:<ctrl>l
@@ -607,13 +620,13 @@
#
SSLCerts:SSL certificates
SSLError:NetSurf failed to verify the authenticity of an SSL certificate. Please verify the details presented below.
-Subject:Subject
-Issuer:Issuer
-Version:Version
-ValidFrom:Valid from
-ValidTo:Valid until
-Type:Type
-Serial:Serial
+Subject:Subject: %s
+Issuer:Issuer: %s
+Version:Version: %ld
+ValidFrom:Valid from: %s
+ValidTo:Valid until: %s
+Type:Type: %i
+Serial:Serial: %ld
Accept:Accept
Reject:Reject
@@ -722,7 +735,7 @@
NoDiscSpace:Not enough space available on disc.
Template:A window template is missing from the Templates file. Please reinstall NetSurf.
HotlistSaveError:The hotlist was unable to be correctly saved.
-HotlistLoadError:The hotlist was unable to be correctly loaded.
+TreeLoadError:The tree was unable to be correctly loaded.
NoDirError:%s is not a directory
NoPathError:To save, drag the icon to a directory display
NoNameError:Please enter a name
Index: !NetSurf/Resources/fr/Messages
===================================================================
--- !NetSurf/Resources/fr/Messages (revision 10834)
+++ !NetSurf/Resources/fr/Messages (working copy)
@@ -189,6 +189,8 @@
New:Nouveau
Expand:Déployer
Collapse:Regrouper
+Tree:Tree
+TreeExport:Export...
# New hotlist entry menu
#
@@ -200,6 +202,7 @@
All:Tout
Folders:Dossiers
Links:Adresses
+Domains:Domains
# Other menus
#
@@ -373,6 +376,13 @@
Date1Week:La semaine dernière
Date2Week:Il y a 2 semaines
Date3Week:Il y a 3 semaines
+Sunday:Sunday
+Monday:Monday
+Tuesday:Tuesday
+Wednesday:Wednesday
+Thursday:Thursday
+Friday:Friday
+Saturday:Saturday
# Download user interface tokens
Index: !NetSurf/Resources/nl/Messages
===================================================================
--- !NetSurf/Resources/nl/Messages (revision 10834)
+++ !NetSurf/Resources/nl/Messages (working copy)
@@ -189,6 +189,8 @@
New:Nieuw
Expand:Uitklappen
Collapse:Inklappen
+Tree:Tree
+TreeExport:Export...
# New hotlist entry menu
#
@@ -200,6 +202,7 @@
All:Alles
Folders:Mappen
Links:Adressen
+Domains:Domains
# Other menus
#
@@ -373,6 +376,13 @@
Date1Week:vorige week
Date2Week:2 weken geleden
Date3Week:3 weken geleden
+Sunday:Sunday
+Monday:Monday
+Tuesday:Tuesday
+Wednesday:Wednesday
+Thursday:Thursday
+Friday:Friday
+Saturday:Saturday
# Download user interface tokens
Index: !NetSurf/Resources/it/Messages
===================================================================
--- !NetSurf/Resources/it/Messages (revision 10834)
+++ !NetSurf/Resources/it/Messages (working copy)
@@ -191,6 +191,8 @@
New:Nuovo
Expand:Espandi
Collapse:Raggruppa
+Tree:Tree
+TreeExport:Export...
# New hotlist entry menu
#
@@ -202,6 +204,7 @@
All:Tutte
Folders:Cartelle
Links:Indirizzi
+Domains:Domains
# Other menus
#
@@ -375,6 +378,13 @@
Date1Week:Ultima settimana
Date2Week:2 settimane fa
Date3Week:3 settimane fa
+Sunday:Sunday
+Monday:Monday
+Tuesday:Tuesday
+Wednesday:Wednesday
+Thursday:Thursday
+Friday:Friday
+Saturday:Saturday
# Download user interface tokens
Index: Makefile.sources
===================================================================
--- Makefile.sources (revision 10834)
+++ Makefile.sources (working copy)
@@ -13,8 +13,9 @@
hubbub_binding.c imagemap.c layout.c list.c table.c textplain.c
S_UTILS := base64.c filename.c hashtable.c http.c locale.c messages.c \
talloc.c url.c utf8.c utils.c useragent.c findresource.c
-S_DESKTOP := knockout.c options.c plot_style.c print.c search.c \
- searchweb.c scroll.c textarea.c tree.c version.c
+S_DESKTOP := cookies.c history_global_core.c hotlist.c knockout.c \
+ options.c plot_style.c print.c search.c searchweb.c scroll.c \
+ sslcert.c textarea.c tree.c tree_url_node.c version.c \
# S_COMMON are sources common to all builds
S_COMMON := $(addprefix content/,$(S_CONTENT)) \
@@ -46,7 +47,7 @@
schedule.c search.c searchweb.c sprite.c sslcert.c \
textarea.c textselection.c theme.c theme_install.c thumbnail.c \
treeview.c ucstables.c uri.c url_complete.c url_protocol.c \
- wimp.c wimp_event.c window.c gui/progress_bar.c \
+ url_suggest.c wimp.c wimp_event.c window.c gui/progress_bar.c \
gui/status_bar.c \
$(addprefix configure/,con_cache.c con_connect.c con_content.c \
con_fonts.c con_home.c con_image.c con_inter.c con_language.c \
@@ -61,22 +62,22 @@
gtk_completion.c gtk_login.c gtk_throbber.c gtk_selection.c \
gtk_history.c gtk_window.c gtk_filetype.c gtk_download.c \
gtk_menu.c gtk_print.c gtk_save.c gtk_search.c gtk_tabs.c \
- gtk_theme.c gtk_toolbar.c sexy_icon_entry.c gtk_compat.c \
+ gtk_theme.c gtk_toolbar.c sexy_icon_entry.c gtk_compat.c \
+ gtk_cookies.c gtk_hotlist.c \
$(addprefix dialogs/,gtk_options.c gtk_about.c gtk_source.c)
S_GTK := $(addprefix gtk/,$(S_GTK)) $(addprefix utils/,container.c)
# code in utils/container.ch is non-universal it seems
# S_WINDOWS are sources purely for the windows build
-S_WINDOWS := about.c bitmap.c download.c filetype.c findfile.c font.c \
- gui.c history.c hotlist.c localhistory.c login.c misc.c plot.c \
- prefs.c schedule.c thumbnail.c tree.c
+S_WINDOWS := about.c bitmap.c download.c filetype.c findfile.c font.c \
+ gui.c localhistory.c login.c misc.c plot.c prefs.c schedule.c \
+ thumbnail.c tree.c
S_WINDOWS := $(addprefix windows/,$(S_WINDOWS))
# S_BEOS are sources purely for the BeOS build
S_BEOS := beos_about.cpp beos_bitmap.cpp beos_fetch_rsrc.cpp \
- beos_filetype.cpp beos_font.cpp beos_gui.cpp beos_history.cpp \
- beos_login.cpp beos_options.cpp beos_plotters.cpp \
- beos_save_complete.cpp \
+ beos_filetype.cpp beos_font.cpp beos_gui.cpp beos_login.cpp \
+ beos_options.cpp beos_plotters.cpp beos_save_complete.cpp \
beos_scaffolding.cpp beos_search.cpp beos_schedule.cpp \
beos_thumbnail.cpp beos_treeview.cpp beos_throbber.cpp \
beos_window.cpp
@@ -101,9 +102,9 @@
# S_FRAMEBUFFER are sources purely for the framebuffer build
-S_FRAMEBUFFER := gui.c framebuffer.c tree.c history.c hotlist.c \
- save.c schedule.c thumbnail.c misc.c bitmap.c filetype.c \
- login.c findfile.c localhistory.c
+S_FRAMEBUFFER := gui.c framebuffer.c tree.c save.c schedule.c \
+ thumbnail.c misc.c bitmap.c filetype.c login.c findfile.c \
+ localhistory.c
S_FRAMEBUFFER_FBTK := fbtk.c event.c fill.c bitmap.c user.c window.c \
text.c scroll.c osk.c
Index: desktop/options.h
===================================================================
--- desktop/options.h (revision 10834)
+++ desktop/options.h (working copy)
@@ -85,6 +85,7 @@
extern int option_scale;
extern bool option_incremental_reflow;
extern unsigned int option_min_reflow_period;
+extern char *option_tree_icons_dir;
extern bool option_core_select_menu;
extern int option_margin_top;
@@ -114,8 +115,4 @@
void options_write(const char *path);
void options_dump(void);
-struct tree *options_load_tree(const char *filename);
-bool options_save_tree(struct tree *tree, const char *filename,
- const char *page_title);
-
#endif
Index: desktop/browser.c
===================================================================
--- desktop/browser.c (revision 10834)
+++ desktop/browser.c (working copy)
@@ -46,6 +46,7 @@
#include "desktop/download.h"
#include "desktop/frames.h"
#include "desktop/history_core.h"
+#include "desktop/hotlist.h"
#include "desktop/gui.h"
#include "desktop/options.h"
#include "desktop/selection.h"
Index: desktop/tree.c
===================================================================
--- desktop/tree.c (revision 10834)
+++ desktop/tree.c (working copy)
@@ -1,5 +1,6 @@
/*
* Copyright 2004 Richard Wilson <not_ginger_matt(a)users.sourceforge.net>
+ * Copyright 2009 Paul Blokus <paul_pl(a)users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -25,772 +26,1385 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "content/urldb.h"
+#include "content/content.h"
+#include "content/hlcache.h"
+#include "desktop/browser.h"
+#include "desktop/textarea.h"
+#include "desktop/textinput.h"
#include "desktop/tree.h"
#include "desktop/options.h"
+#include "desktop/plotters.h"
+#include "render/font.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
+#include "utils/url.h"
-static void tree_draw_node(struct tree *tree, struct node *node, int clip_x,
- int clip_y, int clip_width, int clip_height);
-static struct node_element *tree_create_node_element(struct node *parent,
- node_element_data data);
-static void tree_delete_node_internal(struct tree *tree, struct node *node, bool siblings);
+typedef enum {
+ TREE_NO_DRAG = 0,
+ TREE_SELECT_DRAG,
+ TREE_MOVE_DRAG
+} tree_drag_type;
+
+
+#define MAXIMUM_URL_LENGTH 1024
+
+#define TREE_ICON_SIZE 16
+#define NODE_INSTEP 20
+#define TREE_TEXT_HEIGHT 20
+#define FURNITURE_COLOUR 0x888888
+
+static plot_font_style_t plot_fstyle = {
+ .family = PLOT_FONT_FAMILY_SANS_SERIF,
+ .size = 10240,
+ .weight = 400,
+ .flags = FONTF_NONE,
+ .background = 0xFFFFFF,
+ .foreground = 0x000000
+};
+
+static plot_font_style_t plot_fstyle_selected = {
+ .family = PLOT_FONT_FAMILY_SANS_SERIF,
+ .size = 10240,
+ .weight = 400,
+ .flags = FONTF_NONE,
+ .background = 0x000000,
+ .foreground = 0xEEEEEE
+};
+
+struct node;
+struct tree;
+
+struct node_element_box {
+ int x; /* X offset from origin */
+ int y; /* Y offset from origin */
+ int width; /* Element width */
+ int height; /* Element height */
+};
+
+struct node_element {
+ struct node *parent; /* Parent node */
+ node_element_type type; /* Element type */
+ struct node_element_box box; /* Element bounding box */
+ const char *text; /* Text for the element */
+ void *bitmap; /* Bitmap for the element */
+ struct node_element *next; /* Next node element */
+ unsigned int flag; /* Client specified flag for data
+ being represented */
+ bool editable; /* Whether the node text can be
+ * modified, editable text is deleted
+ * without noticing the tree user
+ */
+};
+
+struct node {
+ bool selected; /* Whether the node is selected */
+ bool expanded; /* Whether the node is expanded */
+ bool folder; /* Whether the node is a folder */
+ bool retain_in_memory; /* Whether the node remains
+ in memory after deletion */
+ bool deleted; /* Whether the node is currently
+ deleted */
+ bool processing; /* Internal flag used when moving */
+ struct node_element_box box; /* Bounding box of all elements */
+ struct node_element data; /* Data to display */
+ struct node *parent; /* Parent entry (NULL for root) */
+ struct node *child; /* First child */
+ struct node *last_child; /* Last child */
+ struct node *previous; /* Previous child of the parent */
+ struct node *next; /* Next child of the parent */
+
+ /* Sorting function for the node (for folder nodes only) */
+ int (*sort) (struct node *, struct node *);
+ /* Gets called for each deleted node_element and on node launch */
+ tree_node_user_callback user_callback;
+ /* User data to be passed to delete_callback */
+ void *callback_data;
+};
+
+struct tree {
+ /* These coordinates are only added to the coordinates passed to the
+ plotters. This means they are invisible to the tree, what has to be
+ taken into account i.e in keyboard/mouse event passing */
+ struct node *root; /* Tree root element */
+ int width; /* Tree width */
+ int height; /* Tree height */
+ unsigned int flags; /* Tree flags */
+ struct text_area *textarea; /* Handle for UTF-8 textarea */
+ bool textarea_drag_start; /* whether the start of a mouse drag
+ was in the textarea */
+ struct node_element *editing; /* Node element being edited */
+
+ bool redraw; /* Flag indicating whether the tree
+ should be redrawn on layout
+ changes */
+ tree_drag_type drag;
+ const struct treeview_table *callbacks;
+ void *client_data; /* User assigned data for the
+ callbacks */
+};
+
+static void tree_delete_node_internal(struct tree *tree, struct node *node,
+ bool siblings);
+static void tree_sort_insert(struct node *parent, struct node *node);
+static void tree_set_node_expanded_all(struct tree *tree, struct node *node,
+ bool expanded);
+static bool tree_set_node_expanded_internal(struct tree *tree,
+ struct node *node, bool expanded, bool folder, bool leaf);
+
+static void tree_draw_node(struct tree *tree, struct node *node,
+ int tree_x, int tree_y,
+ int clip_x, int clip_y, int clip_width, int clip_height);
+static void tree_draw_node_expansion(struct tree *tree, struct node *node,
+ int tree_x, int tree_y);
+static void tree_draw_node_element(struct tree *tree,
+ struct node_element *element, int tree_x, int tree_y);
+
+void tree_launch_selected_internal(struct tree *tree, struct node *node);
+
+static void tree_handle_node_changed(struct tree *tree, struct node *node,
+ bool recalculate_sizes, bool expansion);
+static void tree_handle_node_element_changed(struct tree *tree,
+ struct node_element *element);
+
+static void tree_recalculate_node_element(struct tree *tree,
+ struct node_element *element);
+static void tree_recalculate_node_sizes(struct tree *tree, struct node *node,
+ bool recalculate_sizes);
+static void tree_recalculate_node_positions(struct tree *tree,
+ struct node *root);
+static void tree_recalculate_size(struct tree *tree);
static int tree_get_node_width(struct node *node);
static int tree_get_node_height(struct node *node);
+
+
+static void tree_handle_selection_area(struct tree *tree, int y, int height,
+ bool invert);
static void tree_handle_selection_area_node(struct tree *tree,
- struct node *node, int x, int y, int width, int height,
- bool invert);
+ struct node *node, int y, int height, bool invert);
+static struct node *tree_get_node_at(struct node *root, int x, int y,
+ bool *furniture);
+static struct node_element *tree_get_node_element_at(struct node *node,
+ int x, int y, bool *furniture);
+
+static void tree_move_selected_nodes(struct tree *tree,
+ struct node *destination, bool before);
static void tree_selected_to_processing(struct node *node);
void tree_clear_processing(struct node *node);
-struct node *tree_move_processing_node(struct node *node, struct node *link,
- bool before, bool first);
-struct node *tree_create_leaf_node_shared(struct node *parent, const char *title);
+static struct node *tree_move_processing_node(struct tree *tree,
+ struct node *node, struct node *link, bool before, bool first);
-static int tree_initialising = 0;
+static void tree_stop_edit(struct tree *tree, bool keep_changes);
+static nserror tree_icon_callback(hlcache_handle *handle,
+ const hlcache_event *event, void *pw);
+static void tree_textarea_redraw_request(void *data, int x, int y,
+ int width, int height);
-
/**
- * Initialises a user-created tree
+ * Creates and initialises a new tree.
*
- * \param tree the tree to initialise
+ * \param flags flag word for flags to create the new tree with
+ * \param redraw_request function to be called each time the tree wants to
+ * be redrawn
+ * \param client_data data to be passed to start_redraw and end_redraw
+ * \param root gets updated to point at the root of the tree,
+ * if not NULL
+ * \return the newly created tree, or NULL on memory exhaustion
*/
-void tree_initialise(struct tree *tree) {
+struct tree *tree_create(unsigned int flags,
+ const struct treeview_table *callbacks,
+ void *client_data)
+{
+ struct tree *tree;
+ char *title;
- assert(tree);
+ tree = calloc(sizeof(struct tree), 1);
+ if (tree == NULL) {
+ LOG(("calloc failed"));
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
- tree_set_node_expanded(tree, tree->root, true);
- tree_initialise_nodes(tree, tree->root);
- tree_recalculate_node_positions(tree, tree->root);
- tree_set_node_expanded(tree, tree->root, false);
+ title = strdup("Root");
+ if (title == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ free(tree);
+ return NULL;
+ }
+ tree->root = tree_create_folder_node(NULL, NULL, title,
+ false, false, false);
+ if (tree->root == NULL) {
+ free(title);
+ free(tree);
+ return NULL;
+ }
tree->root->expanded = true;
- tree_recalculate_node_positions(tree, tree->root);
- tree_recalculate_size(tree);
+
+ tree->width = 0;
+ tree->height = 0;
+ tree->flags = flags;
+ tree->textarea = NULL;
+ tree->textarea_drag_start = false;
+ tree->editing = NULL;
+ tree->redraw = false;
+ tree->drag = TREE_NO_DRAG;
+ tree->callbacks = callbacks;
+ tree->client_data = client_data;
+
+ return tree;
}
-
/**
- * Initialises a user-created node structure
+ * Creates a folder node with the specified title, and optionally links it into
+ * the tree.
*
- * \param root the root node to update from
+ * \param tree the owner tree of 'parent', may be NULL
+ * \param parent the parent node, or NULL not to link
+ * \param title the node title (not copied, used directly)
+ * \param editable if true, the node title will be editable
+ * \param retain_in_memory if true, the node will stay in memory after deletion
+ * \param deleted if true, the node is created with the deleted flag
+ * \return the newly created node.
*/
-void tree_initialise_nodes(struct tree *tree, struct node *root) {
+struct node *tree_create_folder_node(struct tree *tree, struct node *parent,
+ const char *title, bool editable, bool retain_in_memory,
+ bool deleted)
+{
struct node *node;
- assert(root);
+ assert(title);
- tree_initialising++;
- for (node = root; node; node = node->next) {
- tree_recalculate_node(tree, node, true);
- if (node->child) {
- tree_initialise_nodes(tree, node->child);
- }
+ node = calloc(sizeof(struct node), 1);
+ if (node == NULL) {
+ LOG(("calloc failed"));
+ warn_user("NoMemory", 0);
+ return NULL;
}
- tree_initialising--;
+ node->folder = true;
+ node->retain_in_memory = retain_in_memory;
+ node->deleted = deleted;
+ node->data.parent = node;
+ node->data.type = NODE_ELEMENT_TEXT;
+ node->data.text = title;
+ node->data.flag = TREE_ELEMENT_TITLE;
+ node->data.editable = editable;
+ node->sort = NULL;
+ node->user_callback = NULL;
- if (tree_initialising == 0)
- tree_recalculate_node_positions(tree, root);
+ tree_recalculate_node_sizes(tree, node, true);
+ if (parent != NULL)
+ tree_link_node(tree, parent, node, false);
+
+ return node;
}
/**
- * Recalculate the node data and redraw the relevant section of the tree.
+ * Creates a leaf node with the specified title, and optionally links it into
+ * the tree.
*
- * \param tree the tree to redraw
- * \param node the node to update
- * \param recalculate_sizes whether the elements have changed
- * \param expansion the request is the result of a node expansion
+ * \param tree the owner tree of 'parent', may be NULL
+ * \param parent the parent node, or NULL not to link
+ * \param title the node title (not copied, used directly)
+ * \param editable if true, the node title will be editable
+ * \param retain_in_memory if true, the node will stay in memory after deletion
+ * \param deleted if true, the node is created with the deleted flag
+ * \return the newly created node.
*/
-void tree_handle_node_changed(struct tree *tree, struct node *node,
- bool recalculate_sizes, bool expansion) {
- int width, height;
+struct node *tree_create_leaf_node(struct tree *tree, struct node *parent,
+ const char *title, bool editable, bool retain_in_memory,
+ bool deleted)
+{
+ struct node *node;
- assert(node);
+ assert(title);
- if ((expansion) && (node->expanded) && (node->child)) {
- tree_set_node_expanded(tree, node->child, false);
- tree_set_node_selected(tree, node->child, false);
+ node = calloc(sizeof(struct node), 1);
+ if (node == NULL) {
+ LOG(("calloc failed"));
+ warn_user("NoMemory", 0);
+ return NULL;
}
+ node->folder = false;
+ node->retain_in_memory = retain_in_memory;
+ node->deleted = deleted;
+ node->data.parent = node;
+ node->data.type = NODE_ELEMENT_TEXT;
+ node->data.text = title;
+ node->data.flag = TREE_ELEMENT_TITLE;
+ node->data.editable = editable;
+ node->sort = NULL;
+ node->user_callback = NULL;
- width = node->box.width;
- height = node->box.height;
- if ((recalculate_sizes) || (expansion))
- tree_recalculate_node(tree, node, true);
- if ((node->box.height != height) || (expansion)) {
- tree_recalculate_node_positions(tree, tree->root);
- tree_redraw_area(tree, 0, node->box.y, 16384, 16384);
- } else {
- width = (width > node->box.width) ? width : node->box.width;
- tree_redraw_area(tree, node->box.x, node->box.y, width, node->box.height);
- }
- if ((recalculate_sizes) || (expansion))
- tree_recalculate_size(tree);
+ tree_recalculate_node_sizes(tree, node, true);
+ if (parent != NULL)
+ tree_link_node(tree, parent, node, false);
+
+ return node;
}
/**
- * Recalculate the node element and redraw the relevant section of the tree.
- * The tree size is not updated.
+ * Creates an empty text node element and links it to a node.
*
- * \param tree the tree to redraw
- * \param element the node element to update
+ * \param parent the parent node
+ * \param type the required element type
+ * \param flag user assigned flag used for searches
+ * \return the newly created element.
*/
-void tree_handle_node_element_changed(struct tree *tree, struct node_element *element) {
- int width, height;
+struct node_element *tree_create_node_element(struct node *parent,
+ node_element_type type, unsigned int flag, bool editable)
+{
+ struct node_element *element;
- assert(element);
-
- width = element->box.width;
- height = element->box.height;
- tree_recalculate_node_element(element);
-
- if (element->box.height != height) {
- tree_recalculate_node(tree, element->parent, false);
- tree_redraw_area(tree, 0, element->box.y, 16384, 16384);
- } else {
- if (element->box.width != width)
- tree_recalculate_node(tree, element->parent, false);
- width = (width > element->box.width) ? width :
- element->box.width;
- tree_redraw_area(tree, element->box.x, element->box.y, width, element->box.height);
- }
+ element = calloc(sizeof(struct node_element), 1);
+ if (element == NULL) return NULL;
+ element->parent = parent;
+ element->flag = flag;
+ element->type = type;
+ element->editable = editable;
+ element->next = parent->data.next;
+ parent->data.next = element;
+ return element;
}
/**
- * Recalculates the size of a node.
+ * Links a node to another node.
*
- * \param node the node to update
- * \param recalculate_sizes whether the node elements have changed
+ * \param tree the tree in which the link takes place, may be NULL
+ * \param link the node to link before/as a child (folders)
+ * or before/after (link)
+ * \param node the node to link
+ * \param before whether to link siblings before or after the supplied node
*/
-void tree_recalculate_node(struct tree *tree, struct node *node, bool recalculate_sizes) {
- struct node_element *element;
- int height;
+void tree_link_node(struct tree *tree, struct node *link, struct node *node,
+ bool before)
+{
+ struct node *parent;
+ bool sort = false;
+
+ assert(link);
assert(node);
- height = node->box.height;
- node->box.width = 0;
- node->box.height = 0;
- if (node->expanded) {
- for (element = &node->data; element; element = element->next) {
- if (recalculate_sizes)
- tree_recalculate_node_element(element);
- node->box.width = (node->box.width >
- element->box.x + element->box.width - node->box.x) ?
- node->box.width :
- element->box.width + element->box.x - node->box.x;
- node->box.height += element->box.height;
+ if ((!link->folder) || (before)) {
+ parent = node->parent = link->parent;
+ if (parent->sort)
+ sort = true;
+ else {
+ if (before) {
+ node->next = link;
+ node->previous = link->previous;
+ if (link->previous != NULL)
+ link->previous->next = node;
+ link->previous = node;
+ if ((parent != NULL) && (parent->child == link))
+ parent->child = node;
+ } else {
+ node->previous = link;
+ node->next = link->next;
+ if (link->next != NULL)
+ link->next->previous = node;
+ link->next = node;
+ if ((parent != NULL) &&
+ (parent->last_child == link))
+ parent->last_child = node;
+ }
}
} else {
- if (recalculate_sizes)
- for (element = &node->data; element; element = element->next)
- tree_recalculate_node_element(element);
- else
- tree_recalculate_node_element(&node->data);
- node->box.width = node->data.box.width;
- node->box.height = node->data.box.height;
+ parent = node->parent = link;
+ if (parent->sort != NULL)
+ sort = true;
+ else {
+ node->next = NULL;
+ if (link->child == NULL) {
+ link->child = link->last_child = node;
+ node->previous = NULL;
+ } else {
+ link->last_child->next = node;
+ node->previous = link->last_child;
+ link->last_child = node;
+ }
+ }
+
}
- if (height != node->box.height) {
- for (; node->parent; node = node->parent);
- if (tree_initialising == 0)
- tree_recalculate_node_positions(tree, node);
- }
+ if (sort)
+ tree_sort_insert(parent, node);
+
+ tree_handle_node_changed(tree, link, false, true);
+
+ node->deleted = false;
}
/**
- * Recalculates the position of a node, its siblings and children.
+ * Delinks a node from the tree structures.
*
- * \param root the root node to update from
+ * \param tree the tree in which the delink takes place, may be NULL
+ * \param node the node to delink
*/
-void tree_recalculate_node_positions(struct tree *tree, struct node *root) {
+void tree_delink_node(struct tree *tree, struct node *node)
+{
struct node *parent;
- struct node *node;
- struct node *child;
- struct node_element *element;
- int y;
- for (node = root; node; node = node->next) {
- if (node->previous) {
- node->box.x = node->previous->box.x;
- node->box.y = node->previous->box.y +
- tree_get_node_height(node->previous);
- } else if ((parent = node->parent)) {
- node->box.x = parent->box.x + NODE_INSTEP;
- node->box.y = parent->box.y +
- parent->box.height;
- for (child = parent->child; child != node;
- child = child->next)
- node->box.y += child->box.height;
- } else {
- node->box.x = tree->no_furniture ? -NODE_INSTEP + 4 : 0;
- node->box.y = -40;
- }
- if (node->expanded) {
- if (node->folder) {
- node->data.box.x = node->box.x;
- node->data.box.y = node->box.y;
- tree_recalculate_node_positions(tree, node->child);
- } else {
- y = node->box.y;
- for (element = &node->data; element;
- element = element->next) {
- if (element->type == NODE_ELEMENT_TEXT_PLUS_SPRITE) {
- element->box.x = node->box.x;
- } else {
- element->box.x = node->box.x + NODE_INSTEP;
- }
- element->box.y = y;
- y += element->box.height;
- }
+ assert(node != NULL);
+
+ /* do not remove the root */
+ if (tree != NULL && node == tree->root)
+ return;
+ if ((tree != NULL) && (tree->editing != NULL)) {
+ parent = tree->editing->parent;
+ while (parent != NULL) {
+ if (node == parent) {
+ tree_stop_edit(tree, false);
+ break;
}
- } else {
- node->data.box.x = node->box.x;
- node->data.box.y = node->box.y;
+ parent = parent->parent;
}
}
+
+ if (node->parent->child == node)
+ node->parent->child = node->next;
+ if (node->parent->last_child == node)
+ node->parent->last_child = node->previous;
+ parent = node->parent;
+ node->parent = NULL;
+
+ if (node->previous != NULL)
+ node->previous->next = node->next;
+ if (node->next != NULL)
+ node->next->previous = node->previous;
+ node->previous = NULL;
+ node->next = NULL;
+
+ tree_handle_node_changed(tree, parent, false, true);
}
+/**
+ * Deletes all nodes of a tree and the tree itself.
+ *
+ * \param tree the tree to be deleted
+ */
+void tree_delete(struct tree *tree)
+{
+ tree_set_redraw(tree, false);
+ if (tree->root->child != NULL)
+ tree_delete_node_internal(tree, tree->root->child, true);
+ free((void *)tree->root->data.text);
+ free(tree->root);
+ free(tree);
+}
+
+
/**
- * Calculates the width of a node including any children
+ * Gets the redraw property of the given tree.
*
- * \param node the node to calculate the height of
- * \return the total width of the node and children
+ * \param tree the tree for which to retrieve the property
+ * \return the redraw property of the tree
*/
-int tree_get_node_width(struct node *node) {
- int width = 0;
- int child_width;
+bool tree_get_redraw(struct tree *tree)
+{
+ return tree->redraw;
+}
- assert(node);
- for (; node; node = node->next) {
- if (width < (node->box.x + node->box.width))
- width = node->box.x + node->box.width;
- if ((node->child) && (node->expanded)) {
- child_width = tree_get_node_width(node->child);
- if (width < child_width)
- width = child_width;
- }
- }
- return width;
+/**
+ * Deletes a node from the tree.
+ *
+ * \param tree the tree to delete from, may be NULL
+ * \param node the node to delete
+ * \param siblings whether to delete all siblings
+ */
+void tree_delete_node(struct tree *tree, struct node *node, bool siblings)
+{
+ int y = node->box.y;
+ tree_delete_node_internal(tree, node, siblings);
+ tree_recalculate_node_positions(tree, tree->root);
+ if (tree->redraw)
+ tree->callbacks->redraw_request(0, y, tree->width, tree->height,
+ tree->client_data);
+ tree_recalculate_size(tree);
}
/**
- * Calculates the height of a node including any children
+ * Deletes a node from the tree.
*
- * \param node the node to calculate the height of
- * \return the total height of the node and children
+ * \param tree the tree to delete from, may be NULL
+ * \param node the node to delete
+ * \param siblings whether to delete all siblings
*/
-int tree_get_node_height(struct node *node) {
- int y1;
+void tree_delete_node_internal(struct tree *tree, struct node *node,
+ bool siblings)
+{
+ struct node *next, *child, *parent;
+ struct node_element *e, *f;
+ node_callback_resp response;
+ struct node_msg_data msg_data;
- assert(node);
+ assert(node != NULL);
- if ((node->child) && (node->expanded)) {
- y1 = node->box.y;
- if (y1 < 0)
- y1 = 0;
- node = node->child;
- while ((node->next) || ((node->child) && (node->expanded))) {
- for (; node->next; node = node->next);
- if ((node->child) && (node->expanded))
- node = node->child;
+ if (tree != NULL && tree->root == node)
+ return;
+
+ next = node->next;
+ parent = node->parent;
+ if (tree != NULL && parent == tree->root)
+ parent = NULL;
+ tree_delink_node(tree, node);
+ child = node->child;
+ node->child = NULL;
+
+ node->deleted = true;
+ if (child != NULL)
+ tree_delete_node_internal(tree, child, true);
+
+ if (!node->retain_in_memory) {
+ node->retain_in_memory = true;
+ for (e = &node->data; e != NULL; e = f) {
+ if (e->text != NULL) {
+ response = NODE_CALLBACK_NOT_HANDLED;
+ if (!e->editable &&
+ node->user_callback != NULL) {
+ msg_data.msg = NODE_DELETE_ELEMENT_TXT;
+ msg_data.flag = e->flag;
+ msg_data.node = node;
+ msg_data.data.text = (void *)e->text;
+ response = node->user_callback(
+ node->callback_data,
+ &msg_data);
+ }
+ if (response != NODE_CALLBACK_HANDLED)
+ free((void *)e->text);
+ e->text = NULL;
+ }
+ if (e->bitmap != NULL) {
+ response = NODE_CALLBACK_NOT_HANDLED;
+ if (node->user_callback != NULL) {
+ msg_data.msg = NODE_DELETE_ELEMENT_IMG;
+ msg_data.flag = e->flag;
+ msg_data.node = node;
+ msg_data.data.bitmap =
+ (void *)e->bitmap;
+ response = node->user_callback(
+ node->callback_data,
+ &msg_data);
+ }
+ /* TODO the type of this field is platform
+ dependent */
+ if (response != NODE_CALLBACK_HANDLED)
+ free(e->bitmap);
+ e->bitmap = NULL;
+ }
+ f = e->next;
+ if (e != &node->data)
+ free(e);
}
- return node->box.y + node->box.height - y1;
- } else {
- return node->box.height;
+ free(node);
}
+
+ if (siblings && next)
+ tree_delete_node_internal(tree, next, true);
+ if ((tree->flags & TREE_DELETE_EMPTY_DIRS) && parent != NULL &&
+ parent->child == NULL && !parent->deleted)
+ tree_delete_node_internal(tree, parent, false);
}
/**
- * Updates all siblinds and descendants of a node to an expansion state.
- * No update is performed for the tree changes.
+ * Sets an icon for a node
*
- * \param node the node to set all siblings and descendants of
+ * \param tree The tree to which node belongs, may be NULL
+ * \param node The node for which the icon is set
+ * \param icon the image to use
+ */
+void tree_set_node_icon(struct tree *tree, struct node *node,
+ hlcache_handle *icon)
+{
+ node->data.type = NODE_ELEMENT_TEXT_PLUS_ICON;
+ tree_update_node_element(tree, &(node->data), NULL, icon);
+}
+
+
+/**
+ * Updates [all siblings and descendants of] a node to an expansion state.
+ *
+ * \param tree the tree to update
+ * \param node the node to set [all siblings and descendants of]
* \param expanded the expansion state to set
+ * \param folder whether to update folders, if this together with leaf
+ * will be false only 'node' will be updated
+ * \param leaf whether to update leaves (check also description for folder)
*/
-void tree_set_node_expanded(struct tree *tree, struct node *node, bool expanded) {
- for (; node; node = node->next) {
+void tree_set_node_expanded(struct tree *tree, struct node *node, bool expanded,
+ bool folder, bool leaf)
+{
+ bool change = tree_set_node_expanded_internal(tree, node, expanded,
+ folder, leaf);
+
+ if (change)
+ tree_handle_node_changed(tree, node, false, true);
+}
+
+
+/**
+ * Updates all siblings and descendants of a node to an expansion state.
+ * No update is performed for the tree changes.
+ *
+ * \param tree the tree to which 'node' belongs
+ * \param node the node to set all siblings and descendants of
+ * \param expanded the expansion state to set
+ */
+void tree_set_node_expanded_all(struct tree *tree, struct node *node,
+ bool expanded)
+{
+ for (; node != NULL; node = node->next) {
if (node->expanded != expanded) {
node->expanded = expanded;
- tree_recalculate_node(tree, node, false);
+ tree_recalculate_node_sizes(tree, node, false);
}
- if ((node->child) && (node->expanded))
- tree_set_node_expanded(tree, node->child, expanded);
+ if ((node->child != NULL) && (node->expanded))
+ tree_set_node_expanded_all(tree, node->child, expanded);
}
}
/**
- * Updates all siblinds and descendants of a node to an expansion state.
+ * Updates [all siblings and descendants of] a node to an expansion state.
*
* \param tree the tree to update
- * \param node the node to set all siblings and descendants of
+ * \param node the node to set [all siblings and descendants of]
* \param expanded the expansion state to set
- * \param folder whether to update folders
- * \param leaf whether to update leaves
- * \return whether any changes were made
+ * \param folder whether to update folders, if this together with leaf
+ * will be false only 'node' will be updated
+ * \param leaf whether to update leaves (check also description for folder)
+ * \return whether any changes were made
*/
-bool tree_handle_expansion(struct tree *tree, struct node *node, bool expanded, bool folder,
- bool leaf) {
- struct node *entry = node;
+bool tree_set_node_expanded_internal(struct tree *tree, struct node *node,
+ bool expanded, bool folder, bool leaf)
+{
bool redraw = false;
+ struct node *end = (folder == false && leaf == false) ?
+ node->next : NULL;
- for (; node; node = node->next) {
+ if (tree->editing != NULL && node == tree->editing->parent)
+ tree_stop_edit(tree, false);
+
+ for (; node != end; node = node->next) {
if ((node->expanded != expanded) && (node != tree->root) &&
- ((folder && (node->folder)) || (leaf && (!node->folder)))) {
+ ((folder && (node->folder)) ||
+ (leaf && (!node->folder)) ||
+ (!folder && !leaf))) {
node->expanded = expanded;
- if (node->child)
- tree_set_node_expanded(tree, node->child, false);
- if ((node->data.next) && (node->data.next->box.height == 0))
- tree_recalculate_node(tree, node, true);
+ if (node->child != NULL)
+ tree_set_node_expanded_all(tree,
+ node->child, false);
+ if ((node->data.next != NULL) &&
+ (node->data.next->box.height == 0))
+ tree_recalculate_node_sizes(tree, node, true);
else
- tree_recalculate_node(tree, node, false);
+ tree_recalculate_node_sizes(tree, node, false);
redraw = true;
}
- if ((node->child) && (node->expanded))
- redraw |= tree_handle_expansion(tree, node->child, expanded, folder, leaf);
+ if ((folder || leaf) && (node->child != NULL) &&
+ (node->expanded))
+ redraw |= tree_set_node_expanded_internal(tree,
+ node->child, expanded, folder, leaf);
}
- if ((entry == tree->root) && (redraw)) {
- tree_recalculate_node_positions(tree, tree->root);
- tree_redraw_area(tree, 0, 0, 16384, 16384);
- tree_recalculate_size(tree);
- }
return redraw;
}
/**
- * Updates all siblinds and descendants of a node to an selected state.
- * The required areas of the tree are redrawn.
+ * Updates a node to an selected state. The required areas of the tree are
+ * redrawn.
*
- * \param tree the tree to update nodes for
+ * \param tree the tree to update nodes for, may be NULL
* \param node the node to set all siblings and descendants of
+ * \param all if true update node together with its siblings and
+ * descendants
* \param selected the selection state to set
*/
-void tree_set_node_selected(struct tree *tree, struct node *node, bool selected) {
- for (; node; node = node->next) {
- if ((node->selected != selected) && (node != tree->root)) {
+void tree_set_node_selected(struct tree *tree, struct node *node, bool all,
+ bool selected)
+{
+ struct node *end;
+
+ if (tree != NULL && node == tree->root)
+ node = tree->root->child;
+ if (node == NULL)
+ return;
+
+ end = all ? NULL : node->next;
+
+ for (; node != end; node = node->next) {
+ if (node->selected != selected) {
node->selected = selected;
- tree_redraw_area(tree, node->box.x, node->box.y, node->box.width,
- node->data.box.height);
+ if (tree != NULL && tree->redraw)
+ tree->callbacks->redraw_request(node->box.x,
+ node->box.y,
+ node->box.width,
+ node->data.box.height,
+ tree->client_data);
}
- if ((node->child) && (node->expanded))
- tree_set_node_selected(tree, node->child, selected);
+ if (all && (node->child != NULL) && (node->expanded))
+ tree_set_node_selected(tree, node->child, all,
+ selected);
}
}
/**
- * Finds a node at a specific location.
+ * Sets the sort function for a node
*
- * \param root the root node to check from
- * \param x the x co-ordinate
- * \param y the y co-ordinate
- * \param furniture whether the returned area was in an elements furniture
- * \return the node at the specified position, or NULL for none
+ * \param tree the tree to which 'node' belongs, may be NULL
+ * \param node the node to be inserted
+ * \param sort pointer to the sorting function
*/
-struct node *tree_get_node_at(struct node *root, int x, int y, bool *furniture) {
- struct node_element *result;
+void tree_set_node_sort_function(struct tree *tree, struct node *node,
+ int (*sort) (struct node *, struct node *))
+{
+ struct node *child;
- if ((result = tree_get_node_element_at(root, x, y, furniture)))
- return result->parent;
- return NULL;
-}
+ node->sort = sort;
+ if (tree != NULL && tree->editing != NULL)
+ tree_stop_edit(tree, false);
-/**
- * Finds a node element at a specific location.
- *
- * \param node the root node to check from
- * \param x the x co-ordinate
- * \param y the y co-ordinate
- * \param furniture whether the returned area was in an elements furniture
- * \return the node at the specified position, or NULL for none
- */
-struct node_element *tree_get_node_element_at(struct node *node, int x, int y,
- bool *furniture) {
- struct node_element *element;
+ /* the node had already some children so they must get sorted */
+ if (node->child != NULL) {
- *furniture = false;
- for (; node; node = node->next) {
- if (node->box.y > y) return NULL;
- if ((node->box.x - NODE_INSTEP < x) && (node->box.y < y) &&
- (node->box.x + node->box.width >= x) &&
- (node->box.y + node->box.height >= y)) {
- if (node->expanded) {
- for (element = &node->data; element;
- element = element->next) {
- if ((element->box.x < x) && (element->box.y < y) &&
- (element->box.x + element->box.width >= x) &&
- (element->box.y + element->box.height >= y))
- return element;
- }
- } else if ((node->data.box.x < x) &&
- (node->data.box.y < y) &&
- (node->data.box.x + node->data.box.width >= x) &&
- (node->data.box.y + node->data.box.height >= y))
- return &node->data;
- if (((node->child) || (node->data.next)) &&
- (node->data.box.x - NODE_INSTEP + 8 < x) &&
- (node->data.box.y + 8 < y) &&
- (node->data.box.x > x) &&
- (node->data.box.y + 32 > y)) {
- *furniture = true;
- return &node->data;
- }
+ child = node->child;
+ node->child = NULL;
+
+ while (child) {
+ tree_sort_insert(node, child);
+ child = child->next;
}
- if ((node->child) && (node->expanded) &&
- ((element = tree_get_node_element_at(node->child, x, y,
- furniture))))
- return element;
}
- return NULL;
+
+ if (tree != NULL)
+ tree_recalculate_node_positions(tree, node->child);
}
-
/**
- * Finds a node element from a node with a specific user_type
+ * Sets the delete callback for a node.
*
- * \param node the node to examine
- * \param user_type the user_type to check for
- * \return the corresponding element
+ * \param node the node for which the callback is set
+ * \param callback the callback functions to be set
+ * \param data user data to be passed to callback
*/
-struct node_element *tree_find_element(struct node *node, node_element_data data) {
- struct node_element *element;
- for (element = &node->data; element; element = element->next)
- if (element->data == data) return element;
- return NULL;
+void tree_set_node_user_callback(struct node *node,
+ tree_node_user_callback callback, void *data)
+{
+ node->user_callback = callback;
+ node->callback_data = data;
}
/**
- * Moves nodes within a tree.
+ * Inserts a node into the correct place according to the parents sort function
*
- * \param tree the tree to process
- * \param link the node to link before/as a child (folders) or before/after (link)
- * \param before whether to link siblings before or after the supplied node
+ * \param parent the node whose child node 'node' becomes
+ * \param node the node to be inserted
*/
-void tree_move_selected_nodes(struct tree *tree, struct node *destination, bool before) {
- struct node *link;
- struct node *test;
- bool error;
+void tree_sort_insert(struct node *parent, struct node *node)
+{
+ struct node *after;
- tree_clear_processing(tree->root);
- tree_selected_to_processing(tree->root);
+ assert(node != NULL);
+ assert(parent != NULL);
+ assert(parent->sort != NULL);
- /* the destination node cannot be a child of any node with the processing flag set */
- error = destination->processing;
- for (test = destination; test; test = test->parent)
- error |= test->processing;
- if (error) {
- tree_clear_processing(tree->root);
- return;
+ after = parent->last_child;
+ while (after && parent->sort(node, after) == -1)
+ after = after->previous;
+
+ if (after != NULL) {
+ if (after->next != NULL)
+ after->next->previous = node;
+ node->next = after->next;
+ node->previous = after;
+ after->next = node;
}
- if ((destination->folder) && (!destination->expanded) && (!before)) {
- destination->expanded = true;
- tree_handle_node_changed(tree, destination, false, true);
+ else {
+ node->previous = NULL;
+ node->next = parent->child;
+ if (parent->child)
+ parent->child->previous = node;
+ parent->child = node;
}
- link = tree_move_processing_node(tree->root, destination, before, true);
- while (link)
- link = tree_move_processing_node(tree->root, link, false, false);
- tree_clear_processing(tree->root);
- tree_recalculate_node_positions(tree, tree->root);
- tree_redraw_area(tree, 0, 0, 16384, 16384);
+ if (node->next == NULL)
+ parent->last_child = node;
+
+ node->parent = parent;
+
}
/**
- * Sets the processing flag to the selection state.
+ * Sets the redraw property to the given value. If redraw is true, the tree will
+ * be redrawn on layout/appearance changes.
*
- * \param node the node to process siblings and children of
+ * \param tree the tree for which the property is set
+ * \param redraw the value to set
*/
-void tree_selected_to_processing(struct node *node) {
- for (; node; node = node->next) {
- node->processing = node->selected;
- if ((node->child) && (node->expanded))
- tree_selected_to_processing(node->child);
- }
+void tree_set_redraw(struct tree *tree, bool redraw)
+{
+ /* the tree might have no graphical representation, do not set the
+ redraw flag in such case */
+ if (tree->callbacks == NULL)
+ return;
+ tree->redraw = redraw;
}
/**
- * Clears the processing flag.
+ * Checks whether a node, its siblings or any children are selected.
*
- * \param node the node to process siblings and children of
+ * \param node the root node to check from
+ * \return whether 'node', its siblings or any children are selected.
*/
-void tree_clear_processing(struct node *node) {
- for (; node; node = node->next) {
- node->processing = false;
- if (node->child)
- tree_clear_processing(node->child);
+bool tree_node_has_selection(struct node *node)
+{
+ for (; node != NULL; node = node->next) {
+ if (node->selected)
+ return true;
+ if ((node->child != NULL) && (node->expanded) &&
+ (tree_node_has_selection(node->child)))
+ return true;
}
+ return false;
}
/**
- * Moves the first node in a tree with the processing flag set.
+ * Returns the current value of the nodes deleted property.
*
- * \param tree the node to move siblings/children of
- * \param link the node to link before/as a child (folders) or before/after (link)
- * \param before whether to link siblings before or after the supplied node
- * \param first whether to always link after the supplied node (ie not inside of folders)
- * \return the node moved
+ * \param node the node to be checked
+ * \return the current value of the nodes deleted property
*/
-struct node *tree_move_processing_node(struct node *node, struct node *link, bool before,
- bool first) {
- struct node *result;
-
- bool folder = link->folder;
- for (; node; node = node->next) {
- if (node->processing) {
- node->processing = false;
- tree_delink_node(node);
- if (!first)
- link->folder = false;
- tree_link_node(link, node, before);
- if (!first)
- link->folder = folder;
- return node;
- }
- if (node->child) {
- result = tree_move_processing_node(node->child, link, before, first);
- if (result)
- return result;
- }
- }
- return NULL;
+bool tree_node_is_deleted(struct node *node)
+{
+ return node->deleted;
}
+
/**
- * Checks whether a node, its siblings or any children are selected.
+ * Returns true if the node is a folder
*
- * \param node the root node to check from
+ * \param node the node to be checked
+ * \return true if the node is a folder, false otherwise
*/
-bool tree_has_selection(struct node *node) {
- for (; node; node = node->next) {
- if (node->selected)
- return true;
- if ((node->child) && (node->expanded) &&
- (tree_has_selection(node->child)))
- return true;
- }
- return false;
+bool tree_node_is_folder(struct node *node)
+{
+ return node->folder;
}
/**
- * Updates the selected state for a region of nodes.
+ * Updates the content of a node_element.
*
- * \param tree the tree to update
- * \param x the minimum x of the selection rectangle
- * \param y the minimum y of the selection rectangle
- * \param width the width of the selection rectangle
- * \param height the height of the selection rectangle
- * \param invert whether to invert the selected state
+ * \param tree the tree owning element, may be NULL
+ * \param element the element to be updated
+ * \param text new text to be set, may be NULL
+ * \param bitmap new bitmap to be set, may be NULL
*/
-void tree_handle_selection_area(struct tree *tree, int x, int y, int width, int height,
- bool invert) {
- assert(tree);
- assert(tree->root);
+void tree_update_node_element(struct tree *tree, struct node_element *element,
+ const char *text, void *bitmap)
+{
- if (!tree->root->child) return;
+ node_callback_resp response;
+ struct node_msg_data msg_data;
- if (width < 0) {
- x += width;
- width = -width;
+ assert(element);
+
+ if (tree != NULL && element == tree->editing)
+ tree_stop_edit(tree, false);
+
+ if (text != NULL && (element->type == NODE_ELEMENT_TEXT ||
+ element->type == NODE_ELEMENT_TEXT_PLUS_ICON)) {
+ if (element->text != NULL) {
+ response = NODE_CALLBACK_NOT_HANDLED;
+ if (!element->editable &&
+ element->parent->user_callback !=
+ NULL) {
+ msg_data.msg = NODE_DELETE_ELEMENT_TXT;
+ msg_data.flag = element->flag;
+ msg_data.node = element->parent;
+ msg_data.data.text = (void *)element->text;
+ response = element->parent->user_callback(
+ element->parent->callback_data,
+ &msg_data);
+ }
+ if (response != NODE_CALLBACK_HANDLED)
+ free((void *)element->text);
+ }
+ element->text = text;
}
- if (height < 0) {
- y += height;
- height = -height;
+
+ if (bitmap != NULL && (element->type == NODE_ELEMENT_BITMAP ||
+ element->type == NODE_ELEMENT_TEXT_PLUS_ICON)) {
+ if (element->bitmap != NULL) {
+ response = NODE_CALLBACK_NOT_HANDLED;
+ if (element->parent->user_callback != NULL) {
+ msg_data.msg = NODE_DELETE_ELEMENT_IMG;
+ msg_data.flag = element->flag;
+ msg_data.node = element->parent;
+ msg_data.data.bitmap = (void *)element->bitmap;
+ response = element->parent->user_callback(
+ element->parent->callback_data,
+ &msg_data);
+ }
+ if (response != NODE_CALLBACK_HANDLED)
+ free(element->bitmap);
+ }
+ element->bitmap = bitmap;
}
- tree_handle_selection_area_node(tree, tree->root->child, x, y, width, height, invert);
+ tree_handle_node_element_changed(tree, element);
}
/**
- * Updates the selected state for a region of nodes.
+ * Returns the node element's text
*
- * \param tree the tree to update
- * \param node the node to update children and siblings of
- * \param x the minimum x of the selection rectangle
- * \param y the minimum y of the selection rectangle
- * \param width the width of the selection rectangle
- * \param height the height of the selection rectangle
- * \param invert whether to invert the selected state
+ * \return the node element's text
*/
-void tree_handle_selection_area_node(struct tree *tree, struct node *node, int x, int y,
- int width, int height, bool invert) {
+const char *tree_node_element_get_text(struct node_element *element)
+{
+ return element->text;
+}
- struct node_element *element;
- struct node *update;
- int x_max, y_max;
- assert(tree);
- assert(node);
+/**
+ * Get the root node of a tree
+ *
+ * \param tree the tree to get the root of
+ * \return the root of the tree
+ */
+struct node *tree_get_root(struct tree *tree)
+{
+ return tree->root;
+}
- x_max = x + width;
- y_max = y + height;
- for (; node; node = node->next) {
- if (node->box.y > y_max) return;
- if ((node->box.x < x_max) && (node->box.y < y_max) &&
- (node->box.x + node->box.width + NODE_INSTEP >= x) &&
- (node->box.y + node->box.height >= y)) {
- update = NULL;
- if (node->expanded) {
- for (element = &node->data; element;
- element = element->next) {
- if ((element->box.x < x_max) && (element->box.y < y_max) &&
- (element->box.x + element->box.width >= x) &&
- (element->box.y + element->box.height >= y)) {
- update = element->parent;
- break;
- }
- }
- } else if ((node->data.box.x < x_max) &&
- (node->data.box.y < y_max) &&
- (node->data.box.x + node->data.box.width >= x) &&
- (node->data.box.y + node->data.box.height >= y))
- update = node->data.parent;
- if ((update) && (node != tree->root)) {
- if (invert) {
- node->selected = !node->selected;
- tree_handle_node_element_changed(tree, &node->data);
- } else if (!node->selected) {
- node->selected = true;
- tree_handle_node_element_changed(tree, &node->data);
- }
- }
- }
- if ((node->child) && (node->expanded))
- tree_handle_selection_area_node(tree, node->child, x, y, width, height,
- invert);
- }
+/**
+ * Returns true if the tree is currently being edited
+ *
+ * \param tree the tree to be checked
+ * \return true if the tree is currently being edited
+ */
+bool tree_is_edited(struct tree *tree)
+{
+ return tree->editing == NULL ? false:true;
}
/**
+ * Returns the first child of a node
+ *
+ * \param node the node to get the child of
+ * \return the nodes first child
+ */
+struct node *tree_node_get_child(struct node *node)
+{
+ return node->child;
+}
+
+
+/**
+ * Returns the closest sibling a node
+ *
+ * \param node the node to get the sibling of
+ * \return the nodes sibling
+ */
+struct node *tree_node_get_next(struct node *node)
+{
+ return node->next;
+}
+
+
+/**
* Redraws a tree.
*
- * \param tree the tree to draw
- * \param clip_x the minimum x of the clipping rectangle
- * \param clip_y the minimum y of the clipping rectangle
- * \param clip_width the width of the clipping rectangle
- * \param clip_height the height of the clipping rectangle
+ * \param tree the tree to draw
+ * \param x X coordinate to draw the tree at
+ * \param y Y coordinate to draw the tree at
+ * \param clip_x the minimum x of the clipping rectangle relative to
+ * the tree origin
+ * \param clip_y the minimum y of the clipping rectangle relative to
+ * the tree origin
+ * \param clip_width the width of the clipping rectangle
+ * \param clip_height the height of the clipping rectangle
*/
-void tree_draw(struct tree *tree, int clip_x, int clip_y, int clip_width,
- int clip_height) {
- assert(tree);
- assert(tree->root);
+void tree_draw(struct tree *tree, int x, int y,
+ int clip_x, int clip_y, int clip_width, int clip_height)
+{
+ int absolute_x, absolute_y;
+ assert(tree != NULL);
+ assert(tree->root != NULL);
- if (!tree->root->child) return;
+ /* don't draw empty trees or trees with redraw flag set to false */
+ if (tree->root->child == NULL || !tree->redraw) return;
- tree_initialise_redraw(tree);
- tree_draw_node(tree, tree->root->child, clip_x,
+ absolute_x = x + clip_x;
+ absolute_y = y + clip_y;
+ plot.rectangle(absolute_x, absolute_y,
+ absolute_x + clip_width, absolute_y + clip_height,
+ plot_style_fill_white);
+ plot.clip(absolute_x, absolute_y,
+ absolute_x + clip_width, absolute_y + clip_height);
+ tree_draw_node(tree, tree->root->child, x, y, clip_x,
clip_y, clip_width, clip_height);
+ if (tree->editing != NULL) {
+ x = x + tree->editing->box.x;
+ y = y + tree->editing->box.y;
+ if (tree->editing->type == NODE_ELEMENT_TEXT_PLUS_ICON)
+ x += NODE_INSTEP;
+ textarea_redraw(tree->textarea, x, y, absolute_x, absolute_y,
+ absolute_x + clip_width,
+ absolute_y + clip_height);
+ }
}
/**
* Redraws a node.
*
- * \param tree the tree to draw
- * \param node the node to draw children and siblings of
- * \param clip_x the minimum x of the clipping rectangle
- * \param clip_y the minimum y of the clipping rectangle
- * \param clip_width the width of the clipping rectangle
- * \param clip_height the height of the clipping rectangle
+ * \param tree the tree to draw
+ * \param node the node to draw children and siblings of
+ * \param tree_x X coordinate of the tree
+ * \param tree_y Y coordinate of the tree
+ * \param clip_x the minimum x of the clipping rectangle
+ * \param clip_y the minimum y of the clipping rectangle
+ * \param clip_width the width of the clipping rectangle
+ * \param clip_height the height of the clipping rectangle
*/
-void tree_draw_node(struct tree *tree, struct node *node, int clip_x, int clip_y,
- int clip_width, int clip_height) {
+void tree_draw_node(struct tree *tree, struct node *node,
+ int tree_x, int tree_y,
+ int clip_x, int clip_y, int clip_width, int clip_height) {
struct node_element *element;
+ struct node *parent;
int x_max, y_max;
+ int x0, y0, x1, y1;
- assert(tree);
- assert(node);
+ assert(tree != NULL);
+ assert(node != NULL);
+
x_max = clip_x + clip_width + NODE_INSTEP;
y_max = clip_y + clip_height;
- if ((node->parent->next) && (node->parent->next->box.y < clip_y))
+ if ((node->parent->next != NULL) &&
+ (node->parent->next->box.y < clip_y))
return;
- for (; node; node = node->next) {
+ for (; node != NULL; node = node->next) {
if (node->box.y > y_max) return;
- if ((node->next) && (!tree->no_furniture))
- tree_draw_line(node->box.x - (NODE_INSTEP / 2),
- node->box.y + (40 / 2), 0,
- node->next->box.y - node->box.y);
+ if ((node->next != NULL) &&
+ (!(tree->flags & TREE_NO_FURNITURE))) {
+ x0 = x1 = tree_x + node->box.x - (NODE_INSTEP / 2);
+ y0 = tree_y + node->box.y + (20 / 2);
+ y1 = y0 + node->next->box.y - node->box.y;
+ plot.line(x0, y0, x1, y1, plot_style_stroke_darkwbasec);
+ }
if ((node->box.x < x_max) && (node->box.y < y_max) &&
- (node->box.x + node->box.width + NODE_INSTEP >= clip_x) &&
+ (node->box.x + node->box.width
+ + NODE_INSTEP >= clip_x) &&
(node->box.y + node->box.height >= clip_y)) {
- if (!tree->no_furniture) {
- if ((node->expanded) && (node->child))
- tree_draw_line(node->box.x + (NODE_INSTEP / 2),
- node->data.box.y + node->data.box.height, 0,
- (40 / 2));
- if ((node->parent) && (node->parent != tree->root) &&
- (node->parent->child == node))
- tree_draw_line(node->parent->box.x + (NODE_INSTEP / 2),
- node->parent->data.box.y +
- node->parent->data.box.height, 0,
- (40 / 2));
- tree_draw_line(node->box.x - (NODE_INSTEP / 2),
- node->data.box.y +
- node->data.box.height - (40 / 2),
- (NODE_INSTEP / 2) - 4, 0);
- tree_draw_node_expansion(tree, node);
+ if (!(tree->flags & TREE_NO_FURNITURE)) {
+ if ((node->expanded) && (node->child != NULL)) {
+ x0 = x1 = tree_x + node->box.x +
+ (NODE_INSTEP / 2);
+ y0 = tree_y + node->data.box.y
+ + node->data.box.height;
+ y1 = y0 + (20 / 2);
+ plot.line(x0, y0, x1, y1,
+ plot_style_stroke_darkwbasec);
+
+ }
+ parent = node->parent;
+ if ((parent != NULL) &&
+ (parent != tree->root) &&
+ (parent->child == node)) {
+ x0 = x1 = tree_x + parent->box.x +
+ (NODE_INSTEP / 2);
+ y0 = tree_y + parent->data.box.y +
+ parent->data.box.height;
+ y1 = y0 + (20 / 2);
+ plot.line(x0, y0, x1, y1,
+ plot_style_stroke_darkwbasec);
+ }
+ x0 = tree_x + node->box.x - (NODE_INSTEP / 2);
+ x1 = x0 + (NODE_INSTEP / 2) - 2;
+ y0 = y1 = tree_y + node->data.box.y +
+ node->data.box.height -
+ (20 / 2);
+ plot.line(x0, y0, x1, y1,
+ plot_style_stroke_darkwbasec);
+ tree_draw_node_expansion(tree, node,
+ tree_x, tree_y);
}
if (node->expanded)
- for (element = &node->data; element;
+ for (element = &node->data; element != NULL;
element = element->next)
- tree_draw_node_element(tree, element);
+ tree_draw_node_element(tree, element,
+ tree_x, tree_y);
else
- tree_draw_node_element(tree, &node->data);
+ tree_draw_node_element(tree, &node->data,
+ tree_x, tree_y);
}
- if ((node->child) && (node->expanded))
- tree_draw_node(tree, node->child, clip_x, clip_y, clip_width,
- clip_height);
+ if ((node->child != NULL) && (node->expanded))
+ tree_draw_node(tree, node->child, tree_x, tree_y,
+ clip_x, clip_y,
+ clip_width, clip_height);
}
}
/**
+ * Draws an elements expansion icon
+ *
+ * \param tree the tree to draw the expansion for
+ * \param element the element to draw the expansion for
+ * \param tree_x X coordinate of the tree
+ * \param tree_y Y coordinate of the tree
+ */
+void tree_draw_node_expansion(struct tree *tree, struct node *node,
+ int tree_x, int tree_y)
+{
+ int x, y;
+
+ assert(tree != NULL);
+ assert(node != NULL);
+
+ if ((node->child != NULL) || (node->data.next != NULL)) {
+ x = tree_x + node->box.x - (NODE_INSTEP / 2) - 4;
+ y = tree_y + node->box.y - (TREE_TEXT_HEIGHT / 2) + 16;
+ plot.rectangle(x, y, x + 9, y + 9, plot_style_fill_white);
+ plot.rectangle(x , y, x + 8, y + 8,
+ plot_style_stroke_darkwbasec);
+ plot.line(x + 2, y + 4, x + 7, y + 4,
+ plot_style_stroke_darkwbasec);
+ if (!node->expanded)
+ plot.line(x + 4, y + 2, x + 4, y + 7,
+ plot_style_stroke_darkwbasec);
+
+ }
+
+}
+
+
+/**
+ * Draws an element, including any expansion icons
+ *
+ * \param tree the tree to draw an element for
+ * \param element the element to draw
+ * \param tree_x X coordinate of the tree
+ * \param tree_y Y coordinate of the tree
+ */
+void tree_draw_node_element(struct tree *tree, struct node_element *element,
+ int tree_x, int tree_y)
+{
+
+ struct bitmap *bitmap = NULL;
+ int x, y, width;
+ bool selected = false;
+ hlcache_handle *icon;
+ plot_font_style_t *fstyle;
+
+ assert(tree != NULL);
+ assert(element != NULL);
+ assert(element->parent != NULL);
+
+ x = tree_x + element->box.x;
+ y = tree_y + element->box.y;
+ width = element->box.width;
+ if (&element->parent->data == element)
+ if (element->parent->selected)
+ selected = true;
+
+ switch (element->type) {
+ case NODE_ELEMENT_TEXT_PLUS_ICON:
+ icon = element->bitmap;
+ if (icon != NULL &&
+ (content_get_status(icon) ==
+ CONTENT_STATUS_READY ||
+ content_get_status(icon) ==
+ CONTENT_STATUS_DONE)) {
+ content_redraw(icon , x, y + 3,
+ TREE_ICON_SIZE, TREE_ICON_SIZE,
+ x, y, x + TREE_ICON_SIZE,
+ y + TREE_ICON_SIZE, 1, 0);
+ }
+
+ x += NODE_INSTEP;
+ width -= NODE_INSTEP;
+
+ /* fall through */
+ case NODE_ELEMENT_TEXT:
+ if (element->text == NULL)
+ break;
+
+ if (element == tree->editing)
+ return;
+
+ if (selected) {
+ fstyle = &plot_fstyle_selected;
+ plot.rectangle(x, y, x + width,
+ y + element->box.height,
+ plot_style_fill_black);
+ } else {
+ fstyle = &plot_fstyle;
+ plot.rectangle(x, y, x + width,
+ y + element->box.height,
+ plot_style_fill_white);
+ }
+
+ plot.text(x + 4, y + TREE_TEXT_HEIGHT * 0.75,
+ element->text, strlen(element->text),
+ fstyle);
+ break;
+ case NODE_ELEMENT_BITMAP:
+ bitmap = element->bitmap;
+ if (bitmap == NULL)
+ break;
+ plot.bitmap(x, y, element->box.width - 1,
+ element->box.height - 2,
+ bitmap, 0xFFFFFF, BITMAPF_NONE);
+ if (!(tree->flags & TREE_NO_FURNITURE))
+ plot.rectangle(x, y, x + element->box.width - 1,
+ y + element->box.height - 3,
+ plot_style_stroke_darkwbasec);
+
+ break;
+ }
+
+}
+
+
+/**
+ * Finds a node element from a node with a specific user_type
+ *
+ * \param node the node to examine
+ * \param flag user assinged flag used is searches
+ * \param after if this is not NULL the search will start after the given
+ * node_element
+ * \return the corresponding element
+ */
+struct node_element *tree_node_find_element(struct node *node,
+ unsigned int flag, struct node_element *after)
+{
+ struct node_element *element;
+
+ if (after == NULL)
+ element = &node->data;
+ else {
+ assert(after->parent == node);
+ element = after->next;
+ }
+
+ for (; element != NULL; element = element->next)
+ if (element->flag == flag) return element;
+
+ return NULL;
+}
+
+
+/**
+ * Deletes all selected nodes from the tree.
+ *
+ * \param tree the tree to delete from
+ * \param node the node to delete
+ */
+void tree_delete_selected_nodes(struct tree *tree, struct node *node)
+{
+ struct node *next;
+
+ if (node == tree->root) {
+ if (node->child != NULL)
+ tree_delete_selected_nodes(tree, node->child);
+ return;
+ }
+
+ while (node != NULL) {
+ next = node->next;
+ if (node->selected)
+ tree_delete_node(tree, node, false);
+ else if (node->child != NULL)
+ tree_delete_selected_nodes(tree, node->child);
+ node = next;
+ }
+}
+
+
+/**
+ * Returns the selected node, or NULL if multiple nodes are selected.
+ *
+ * \param node the node to search sibling and children
+ * \return the selected node, or NULL if multiple nodes are selected
+ */
+struct node *tree_get_selected_node(struct node *node)
+{
+ struct node *result = NULL;
+ struct node *temp;
+
+ for (; node != NULL; node = node->next) {
+ if (node->selected) {
+ if (result != NULL)
+ return NULL;
+ result = node;
+ }
+ if ((node->child != NULL) && (node->expanded)) {
+ temp = tree_get_selected_node(node->child);
+ if (temp != NULL) {
+ if (result != NULL)
+ return NULL;
+ else
+ result = temp;
+ }
+ }
+ }
+ return result;
+}
+
+
+/**
* Gets link characteristics to insert a node at a specified position.
*
* \param tree the tree to find link information for
* \param x the x co-ordinate
* \param y the y co-ordinate
* \param before set to whether the node should be linked before on exit
- * \return the node to link with
+ * \return the node to link with
*/
-struct node *tree_get_link_details(struct tree *tree, int x, int y, bool *before) {
+struct node *tree_get_link_details(struct tree *tree, int x, int y,
+ bool *before)
+{
struct node *node = NULL;
bool furniture;
- assert(tree);
- assert(tree->root);
+ assert(tree != NULL);
+ assert(tree->root != NULL);
*before = false;
- if (tree->root->child)
+ if (tree->root->child != NULL)
node = tree_get_node_at(tree->root->child, x, y, &furniture);
- if ((!node) || (furniture))
+ if ((node == NULL) || (furniture))
return tree->root;
if (y < (node->box.y + (node->box.height / 2))) {
*before = true;
- } else if ((node->folder) && (node->expanded) && (node->child)) {
+ } else if ((node->folder) && (node->expanded) &&
+ (node->child != NULL)) {
node = node->child;
*before = true;
}
@@ -799,527 +1413,1185 @@
/**
- * Links a node into the tree.
+ * Launches all the selected nodes of the tree
*
- * \param link the node to link before/as a child (folders) or before/after (link)
- * \param node the node to link
- * \param before whether to link siblings before or after the supplied node
+ * \param tree the tree for which all nodes will be launched
*/
-void tree_link_node(struct node *link, struct node *node, bool before) {
- assert(link);
- assert(node);
+void tree_launch_selected(struct tree *tree)
+{
+ if (tree->root->child != NULL)
+ tree_launch_selected_internal(tree, tree->root->child);
+}
- if ((!link->folder) || (before)) {
- node->parent = link->parent;
- if (before) {
- node->next = link;
- node->previous = link->previous;
- if (link->previous) link->previous->next = node;
- link->previous = node;
- if ((link->parent) && (link->parent->child == link))
- link->parent->child = node;
- } else {
- node->previous = link;
- node->next = link->next;
- if (link->next) link->next->previous = node;
- link->next = node;
+
+/**
+ * Launches all the selected nodes of the tree
+ *
+ * \param tree the tree for which all nodes will be launched
+ * \param node the node which will be checked together with its children
+ */
+void tree_launch_selected_internal(struct tree *tree, struct node *node)
+{
+ struct node_msg_data msg_data;
+
+ for (; node != NULL; node = node->next) {
+ if (node->selected && node->user_callback != NULL) {
+ msg_data.msg = NODE_LAUNCH;
+ msg_data.flag = TREE_ELEMENT_TITLE;
+ msg_data.node = node;
+ node->user_callback(node->callback_data, &msg_data);
}
- } else {
- if (!link->child) {
- link->child = link->last_child = node;
- node->previous = NULL;
- } else {
- link->last_child->next = node;
- node->previous = link->last_child;
- link->last_child = node;
- }
- node->parent = link;
- node->next = NULL;
+ if (node->child != NULL)
+ tree_launch_selected_internal(tree, node->child);
}
- node->deleted = false;
}
/**
- * Delinks a node from the tree.
+ * Handles a mouse action for a tree
*
- * \param node the node to delink
+ * \param tree the tree to handle a click for
+ * \param mouse the mouse state
+ * \param x X coordinate of mouse action
+ * \param y Y coordinate of mouse action
+ * \return whether the click was handled
*/
-void tree_delink_node(struct node *node) {
- assert(node);
+bool tree_mouse_action(struct tree *tree, browser_mouse_state mouse, int x,
+ int y)
+{
+ bool furniture;
+ struct node *node;
+ struct node *last;
+ struct node_element *element;
+ struct node_msg_data msg_data;
- if (node->parent) {
- if (node->parent->child == node)
- node->parent->child = node->next;
- if (node->parent->last_child == node)
- node->parent->last_child = node->previous;
- if (node->parent->child == NULL) {
- /* don't contract top-level node */
- if (node->parent->parent)
- node->parent->expanded = false;
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+
+ if (tree->root->child == NULL)
+ return true;
+
+ element = tree_get_node_element_at(tree->root->child, x, y, &furniture);
+
+ /* pass in-textarea mouse action and drags which started in it
+ to the textarea */
+ if (tree->editing != NULL) {
+ int x0, x1, y0, y1;
+ x0 = tree->editing->box.x;
+ if (tree->editing->type == NODE_ELEMENT_TEXT_PLUS_ICON)
+ x0 += NODE_INSTEP;
+ x1 = tree->editing->box.x + tree->editing->box.width;
+ y0 = tree->editing->box.y;
+ y1 = tree->editing->box.y + tree->editing->box.height;
+
+ if (tree->textarea_drag_start &&
+ (mouse & (BROWSER_MOUSE_HOLDING_1 |
+ BROWSER_MOUSE_HOLDING_2))) {
+
+ textarea_mouse_action(tree->textarea, mouse,
+ x - x0, y - y0);
+ return true;
}
- node->parent = NULL;
+
+
+
+ if ((x >= x0) && (x < x1) && (y >= y0) && (y < y1)) {
+
+ if (mouse & (BROWSER_MOUSE_DRAG_1 |
+ BROWSER_MOUSE_DRAG_2))
+ tree->textarea_drag_start = true;
+ else
+ tree->textarea_drag_start = false;
+ textarea_mouse_action(tree->textarea, mouse,
+ x - x0, y - y0);
+ return true;
+
+ }
}
- if (node->previous)
- node->previous->next = node->next;
- if (node->next)
- node->next->previous = node->previous;
- node->previous = NULL;
- node->next = NULL;
+
+ tree->textarea_drag_start = false;
+
+ /* we are not interested in the drag path or in mouse presses, return */
+ if (mouse & (BROWSER_MOUSE_HOLDING_1 | BROWSER_MOUSE_HOLDING_2 |
+ BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2))
+ return true;
+
+ /* cancel edit */
+ if (tree->editing != NULL)
+ tree_stop_edit(tree, false);
+
+
+
+ /* no item either means cancel selection on (select) click or a drag */
+ if (element == NULL) {
+ if (tree->flags & TREE_SINGLE_SELECT) {
+ tree_set_node_selected(tree, tree->root->child, true,
+ false);
+ return true;
+ }
+ if (mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_DRAG_1))
+ tree_set_node_selected(tree, tree->root->child, true,
+ false);
+ if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) {
+
+ /* TODO: the tree window has to scroll the tree when
+ mouse reaches border while dragging this isn't
+ solved for the browser window too.
+ */
+ tree->drag = TREE_SELECT_DRAG;
+ }
+ return true;
+ }
+
+ node = element->parent;
+
+ /* click on furniture or double click on folder toggles node expansion
+ */
+ if (((furniture) && (mouse & (BROWSER_MOUSE_CLICK_1 |
+ BROWSER_MOUSE_CLICK_2))) ||
+ ((!furniture) && (node->child != NULL) &&
+ (mouse & BROWSER_MOUSE_DOUBLE_CLICK))) {
+
+ /* clear any selection */
+ tree_set_node_selected(tree, tree->root->child, true, false);
+
+ /* expand / contract node and redraw */
+ tree_set_node_expanded(tree, node, !node->expanded,
+ false, false);
+
+ /* find the last child node if expanded */
+ last = node;
+ if ((last->child != NULL) && (last->expanded)) {
+ last = last->child;
+ while ((last->next != NULL) ||
+ ((last->child != NULL) &&
+ (last->expanded))) {
+ if (last->next != NULL)
+ last = last->next;
+ else
+ last = last->child;
+ }
+ }
+ /* scroll to the bottom element then back to the top */
+ element = &last->data;
+ if (last->expanded)
+ for (; element->next != NULL; element = element->next);
+ tree->callbacks->scroll_visible(element->box.y,
+ element->box.height,
+ tree->client_data);
+ tree->callbacks->scroll_visible(node->data.box.y,
+ node->data.box.height,
+ tree->client_data);
+ return true;
+ }
+
+ /* no use for any other furniture click */
+ if (furniture)
+ return true;
+
+ /* single/double ctrl+click or alt+click starts editing */
+ if ((element->editable) && (!tree->editing) &&
+ ((element->type == NODE_ELEMENT_TEXT) ||
+ (element->type == NODE_ELEMENT_TEXT_PLUS_ICON)) &&
+ (mouse & (BROWSER_MOUSE_CLICK_1 |
+ BROWSER_MOUSE_DOUBLE_CLICK)) &&
+ (mouse & BROWSER_MOUSE_MOD_2 ||
+ mouse & BROWSER_MOUSE_MOD_3)) {
+ tree_set_node_selected(tree, tree->root->child, true, false);
+ tree_start_edit(tree, element);
+ return true;
+ }
+
+ /* double click launches the leaf */
+ if (mouse & BROWSER_MOUSE_DOUBLE_CLICK) {
+ if (node->user_callback == NULL)
+ return false;
+ msg_data.msg = NODE_LAUNCH;
+ msg_data.flag = TREE_ELEMENT_TITLE;
+ msg_data.node = node;
+ if (node->user_callback(node->callback_data, &msg_data) !=
+ NODE_CALLBACK_HANDLED)
+ return false;
+
+ return true;
+ }
+
+ /* single click (select) cancels current selection and selects item */
+ if (mouse & BROWSER_MOUSE_CLICK_1 || (mouse & BROWSER_MOUSE_CLICK_2 &&
+ tree->flags & TREE_SINGLE_SELECT)) {
+ if (tree->flags & TREE_NO_SELECT)
+ return true;
+ if (!node->selected) {
+ tree_set_node_selected(tree, tree->root->child, true,
+ false);
+ node->selected = true;
+ tree_handle_node_element_changed(tree, &node->data);
+ }
+ return true;
+ }
+
+ /* single click (adjust) toggles item selection */
+ if (mouse & BROWSER_MOUSE_CLICK_2) {
+ if (tree->flags & TREE_NO_SELECT)
+ return true;
+ node->selected = !node->selected;
+ tree_handle_node_element_changed(tree, &node->data);
+ return true;
+ }
+
+ /* drag starts a drag operation */
+ if ((!tree->editing) && (mouse & (BROWSER_MOUSE_DRAG_1 |
+ BROWSER_MOUSE_DRAG_2))) {
+ if (tree->flags & TREE_NO_DRAGS)
+ return true;
+
+ if (!node->selected) {
+ tree_set_node_selected(tree, tree->root->child, true,
+ false);
+ node->selected = true;
+ tree_handle_node_element_changed(tree, &node->data);
+ }
+
+ tree->drag = TREE_MOVE_DRAG;
+
+ return true;
+ }
+
+
+ return false;
}
/**
- * Deletes all selected node from the tree.
+ * Handle the end of a drag operation
*
- * \param tree the tree to delete from
- * \param node the node to delete
+ * \param tree the tree on which the drag was performed
+ * \param mouse mouse state during drag end
+ * \param x0 x coordinate of drag start
+ * \param y0 y coordinate of drag start
+ * \param x1 x coordinate of drag end
+ * \param y1 y coordinate of drag end
*/
-void tree_delete_selected_nodes(struct tree *tree, struct node *node) {
- struct node *next;
+void tree_drag_end(struct tree *tree, browser_mouse_state mouse, int x0, int y0,
+ int x1, int y1)
+{
- while (node) {
- next = node->next;
- if ((node->selected) && (node != tree->root))
- tree_delete_node(tree, node, false);
- else if (node->child)
- tree_delete_selected_nodes(tree, node->child);
- node = next;
+ bool before;
+ struct node *node;
+ int x, y;
+
+ if (tree->textarea_drag_start) {
+ x = tree->editing->box.x;
+ y = tree->editing->box.y;
+ if (tree->editing->type == NODE_ELEMENT_TEXT_PLUS_ICON)
+ x += NODE_INSTEP;
+ textarea_drag_end(tree->textarea, mouse, x1 - x, y1 - y);
}
+
+ tree->textarea_drag_start = false;
+
+ switch (tree->drag) {
+ case TREE_NO_DRAG:
+ break;
+ case TREE_SELECT_DRAG:
+ tree_handle_selection_area(tree, y0, y1 - y0,
+ (mouse | BROWSER_MOUSE_HOLDING_2));
+ break;
+ case TREE_MOVE_DRAG:
+ if (!(tree->flags & TREE_MOVABLE))
+ return;
+ node = tree_get_link_details(tree, x1, y1, &before);
+ tree_move_selected_nodes(tree, node, before);
+ break;
+ }
+
+ tree->drag = TREE_NO_DRAG;
}
/**
- * Deletes a node from the tree.
+ * Key press handling for a tree.
*
- * \param tree the tree to delete from
- * \param node the node to delete
- * \param siblings whether to delete all siblings
+ * \param tree The tree which got the keypress
+ * \param key The ucs4 character codepoint
+ * \return true if the keypress is dealt with, false otherwise.
*/
-void tree_delete_node(struct tree *tree, struct node *node, bool siblings) {
- tree_delete_node_internal(tree, node, siblings);
- if (tree->root)
- tree_recalculate_node_positions(tree, tree->root);
- tree_redraw_area(tree, 0, 0, 16384, 16384); /* \todo correct area */
- tree_recalculate_size(tree);
+bool tree_keypress(struct tree *tree, uint32_t key)
+{
+
+ if (tree->editing != NULL)
+ switch (key) {
+ case KEY_ESCAPE:
+ tree_stop_edit(tree, false);
+ return true;
+ case KEY_NL:
+ tree_stop_edit(tree, true);
+ return true;
+ default:
+ return textarea_keypress(tree->textarea, key);
+ }
+
+ return false;
}
/**
- * Deletes a node from the tree.
+ * Alphabetical comparison function for nodes
*
- * \param tree the tree to delete from
- * \param node the node to delete
- * \param siblings whether to delete all siblings
+ * \param n1 first node to compare
+ * \param n2 first node to compare
+ * \return 0 if equal, greater then zero if n1 > n2,
+ * less then zero if n2 < n1
*/
-void tree_delete_node_internal(struct tree *tree, struct node *node, bool siblings) {
- struct node *next, *child;
- struct node_element *e, *f, *domain, *path;
- const char *domain_t, *path_t, *name_t;
- char *space;
+int tree_alphabetical_sort(struct node *n1, struct node *n2)
+{
+ return strcmp(n1->data.text, n2->data.text);
+}
+
+/**
+ * Recalculate the node data and redraw the relevant section of the tree.
+ *
+ * \param tree the tree to redraw, may be NULL
+ * \param node the node to update
+ * \param recalculate_sizes whether the elements have changed
+ * \param expansion the request is the result of a node expansion
+ */
+void tree_handle_node_changed(struct tree *tree, struct node *node,
+ bool recalculate_sizes, bool expansion)
+{
+ int width, height, tree_height;
+
assert(node);
- if (tree->temp_selection == node)
- tree->temp_selection = NULL;
- if (tree->root == node)
- tree->root = NULL;
+ width = node->box.width;
+ height = node->box.height;
+ tree_height = tree->height;
+ if ((recalculate_sizes) || (expansion))
+ tree_recalculate_node_sizes(tree, node, true);
+ if (tree != NULL) {
+ if ((node->box.height != height) || (expansion)) {
+ tree_recalculate_node_positions(tree, tree->root);
+ tree_recalculate_size(tree);
+ tree_height = (tree_height > tree->height) ?
+ tree_height : tree->height;
+ if (tree->redraw)
+ tree->callbacks->redraw_request(0, node->box.y,
+ tree->width,
+ tree_height - node->box.y,
+ tree->client_data);
+ } else {
+ width = (width > node->box.width) ?
+ width : node->box.width;
+ if (tree->redraw)
+ tree->callbacks->redraw_request(node->box.x,
+ node->box.y,
+ width, node->box.height,
+ tree->client_data);
+ if (recalculate_sizes)
+ tree_recalculate_size(tree);
+ }
+ }
+}
- next = node->next;
- tree_delink_node(node);
- child = node->child;
- node->child = NULL;
- if (child)
- tree_delete_node_internal(tree, child, true);
- if (!node->retain_in_memory) {
- node->retain_in_memory = true;
- for (e = &node->data; e; e = f) {
- if (e->text) {
- /* we don't free non-editable titles or URLs */
- if ((node->editable) || (node->folder))
- free((void *)e->text);
- else {
- /* only reset non-deleted items */
- if (!node->deleted) {
- if (e->data == TREE_ELEMENT_URL) {
- /* reset URL characteristics */
- urldb_reset_url_visit_data(e->text);
- } else if (e->data == TREE_ELEMENT_NAME) {
- /* get the rest of the cookie data */
- domain = tree_find_element(node,
- TREE_ELEMENT_DOMAIN);
- path = tree_find_element(node,
- TREE_ELEMENT_PATH);
- if (domain && path) {
- domain_t = domain->text +
- strlen(messages_get(
- "TreeDomain")) - 4;
- space = strchr(domain_t, ' ');
- if (space)
- *space = '\0';
- path_t = path->text +
- strlen(messages_get(
- "TreePath")) - 4;
- space = strchr(path_t, ' ');
- if (space)
- *space = '\0';
- name_t = e->text;
- urldb_delete_cookie(
- domain_t,
- path_t,
- name_t);
- }
- }
- }
+/**
+ * Recalculate the node element and redraw the relevant section of the tree.
+ * The tree size is not updated.
+ *
+ * \param tree the tree to redraw, may be NULL
+ * \param element the node element to update
+ */
+void tree_handle_node_element_changed(struct tree *tree,
+ struct node_element *element)
+{
+ int width, height;
- if (e->data != TREE_ELEMENT_TITLE &&
- e->data != TREE_ELEMENT_URL) {
- free((void *)e->text);
- e->text = NULL;
- }
- }
+ assert(element != NULL);
+
+ width = element->box.width;
+ height = element->box.height;
+ tree_recalculate_node_element(tree, element);
+
+ if (element->box.height != height) {
+ tree_recalculate_node_sizes(tree, element->parent, false);
+ if (tree != NULL && tree->redraw)
+ tree->callbacks->redraw_request(0, element->box.y,
+ tree->width + element->box.width -
+ width,
+ tree->height - element->box.y +
+ element->box.height - height,
+ tree->client_data);
+ } else {
+ if (element->box.width != width)
+ tree_recalculate_node_sizes(tree, element->parent,
+ false);
+ if (tree != NULL) {
+ width = (width > element->box.width) ? width :
+ element->box.width;
+ if (tree->redraw)
+ tree->callbacks->redraw_request(element->box.x,
+ element->box.y,
+ width, element->box.height,
+ tree->client_data);
+ }
+ }
+}
+
+
+/**
+ * Recalculates the dimensions of a node element.
+ *
+ * \param tree the tree to which the element belongs, may be NULL
+ * \param element the element to recalculate
+ */
+void tree_recalculate_node_element(struct tree *tree,
+ struct node_element *element)
+{
+ struct bitmap *bitmap = NULL;
+ int width, height;
+
+ assert(element != NULL);
+
+ switch (element->type) {
+ case NODE_ELEMENT_TEXT_PLUS_ICON:
+ case NODE_ELEMENT_TEXT:
+ if(element->text == NULL)
+ break;
+ if (tree != NULL && element == tree->editing)
+ textarea_get_dimensions(tree->textarea,
+ &element->box.width, NULL);
+ else
+ nsfont.font_width(&plot_fstyle,
+ element->text,
+ strlen(element->text),
+ &element->box.width);
+ element->box.width += 8;
+ element->box.height = TREE_TEXT_HEIGHT;
+ if (element->type == NODE_ELEMENT_TEXT_PLUS_ICON)
+ element->box.width += NODE_INSTEP;
+ break;
+ case NODE_ELEMENT_BITMAP:
+ bitmap = element->bitmap;
+ if (bitmap != NULL) {
+ width = bitmap_get_width(bitmap);
+ height = bitmap_get_height(bitmap);
+ element->box.width = width + 1;
+ element->box.height = height + 2;
+ } else {
+ element->box.width = 0;
+ element->box.height = 0;
}
- if (e->sprite) {
- /* TODO the type of this field is platform dependent */
- free(e->sprite); /* \todo platform specific bits */
- e->sprite = NULL;
- }
- f = e->next;
- if (e != &node->data)
- free(e);
+ break;
+ }
+}
+
+
+/**
+ * Recalculates the size of a node.
+ *
+ * \param tree the tree to which node belongs, may be NULL
+ * \param node the node to update
+ * \param recalculate_sizes whether the node elements have changed
+ */
+void tree_recalculate_node_sizes(struct tree *tree, struct node *node,
+ bool recalculate_sizes)
+{
+ struct node_element *element;
+ int width, height;
+
+ assert(node);
+
+ width = node->box.width;
+ height = node->box.height;
+ node->box.width = 0;
+ node->box.height = 0;
+ if (node->expanded) {
+ for (element = &node->data; element != NULL;
+ element = element->next) {
+ if (recalculate_sizes)
+ tree_recalculate_node_element(tree, element);
+ node->box.width = (node->box.width > element->box.x +
+ element->box.width - node->box.x) ?
+ node->box.width :
+ element->box.width + element->box.x -
+ node->box.x;
+ node->box.height += element->box.height;
}
- free(node);
} else {
- node->deleted = true;
+ if (recalculate_sizes)
+ for (element = &node->data; element != NULL;
+ element = element->next)
+ tree_recalculate_node_element(tree, element);
+ else
+ tree_recalculate_node_element(tree, &node->data);
+ node->box.width = node->data.box.width;
+ node->box.height = node->data.box.height;
}
- if (siblings && next)
- tree_delete_node_internal(tree, next, true);
+
+ if (tree != NULL && height != node->box.height)
+ tree_recalculate_node_positions(tree, tree->root);
}
+
/**
- * Creates a folder node with the specified title, and links it into the tree.
+ * Recalculates the position of a node, its siblings and children.
*
- * \param parent the parent node, or NULL not to link
- * \param title the node title (copied)
- * \return the newly created node.
+ * \param tree the tree to which 'root' belongs
+ * \param root the root node to update from
*/
-struct node *tree_create_folder_node(struct node *parent, const char *title) {
+void tree_recalculate_node_positions(struct tree *tree, struct node *root)
+{
+ struct node *parent;
struct node *node;
+ struct node *child;
+ struct node_element *element;
+ int y;
+ bool has_icon;
- assert(title);
+ for (node = root; node != NULL; node = node->next) {
- node = calloc(sizeof(struct node), 1);
- if (!node) return NULL;
- node->editable = true;
- node->folder = true;
- node->data.parent = node;
- node->data.type = NODE_ELEMENT_TEXT;
- node->data.text = squash_whitespace(title);
- node->data.data = TREE_ELEMENT_TITLE;
- tree_set_node_sprite_folder(node);
- if (parent)
- tree_link_node(parent, node, false);
- return node;
+ parent = node->parent;
+
+ if (node->previous != NULL) {
+ node->box.x = node->previous->box.x;
+ node->box.y = node->previous->box.y +
+ tree_get_node_height(node->previous);
+ } else if (parent != NULL) {
+ node->box.x = parent->box.x + NODE_INSTEP;
+ node->box.y = parent->box.y +
+ parent->box.height;
+ for (child = parent->child; child != node;
+ child = child->next)
+ node->box.y += child->box.height;
+ } else {
+ node->box.x = tree->flags & TREE_NO_FURNITURE
+ ? -NODE_INSTEP + 4 : 0;
+ node->box.y = -20;
+ }
+
+ if (!node->expanded) {
+ node->data.box.x = node->box.x;
+ node->data.box.y = node->box.y;
+ continue;
+ }
+
+ if (node->folder) {
+ node->data.box.x = node->box.x;
+ node->data.box.y = node->box.y;
+ tree_recalculate_node_positions(tree,
+ node->child);
+ } else {
+ y = node->box.y;
+ has_icon = false;
+ for (element = &node->data; element != NULL;
+ element = element->next)
+ if (element->type ==
+ NODE_ELEMENT_TEXT_PLUS_ICON) {
+ has_icon = true;
+ break;
+ }
+
+ for (element = &node->data; element != NULL;
+ element = element->next) {
+ element->box.x = node->box.x;
+ if (element->type !=
+ NODE_ELEMENT_TEXT_PLUS_ICON &&
+ has_icon)
+ element->box.x += NODE_INSTEP;
+ element->box.y = y;
+ y += element->box.height;
+ }
+ }
+
+ }
}
/**
- * Creates a leaf node with the specified title, and links it into the tree.
+ * Recalculates the size of a tree.
*
- * \param parent the parent node, or NULL not to link
- * \param title the node title (copied)
- * \return the newly created node.
+ * \param tree the tree to recalculate
*/
-struct node *tree_create_leaf_node(struct node *parent, const char *title) {
- struct node *node;
+void tree_recalculate_size(struct tree *tree)
+{
+ int width, height;
- assert(title);
+ assert(tree != NULL);
- node = calloc(sizeof(struct node), 1);
- if (!node) return NULL;
- node->folder = false;
- node->data.parent = node;
- node->data.type = NODE_ELEMENT_TEXT;
- node->data.text = strdup(squash_whitespace(title));
- node->data.data = TREE_ELEMENT_TITLE;
- node->editable = true;
- if (parent)
- tree_link_node(parent, node, false);
- return node;
+
+ width = tree->width;
+ height = tree->height;
+
+ tree->width = tree_get_node_width(tree->root);
+ tree->height = tree_get_node_height(tree->root);
+
+ if ((width != tree->width) || (height != tree->height))
+ tree->callbacks->resized(tree, tree->width, tree->height,
+ tree->client_data);
}
/**
- * Creates a leaf node with the specified title, and links it into the tree.
+ * Calculates the width of a node including any children
*
- * \param parent the parent node, or NULL not to link
- * \param title the node title
- * \return the newly created node.
+ * \param node the node to calculate the height of
+ * \return the total width of the node and children
*/
-struct node *tree_create_leaf_node_shared(struct node *parent, const char *title) {
- struct node *node;
+int tree_get_node_width(struct node *node)
+{
+ int width = 0;
+ int child_width;
- assert(title);
+ assert(node != NULL);
- node = calloc(sizeof(struct node), 1);
- if (!node) return NULL;
- node->folder = false;
- node->data.parent = node;
- node->data.type = NODE_ELEMENT_TEXT;
- node->data.text = title;
- node->data.data = TREE_ELEMENT_TITLE;
- node->editable = false;
- if (parent)
- tree_link_node(parent, node, false);
- return node;
+ for (; node != NULL; node = node->next) {
+ if (width < (node->box.x + node->box.width))
+ width = node->box.x + node->box.width;
+ if ((node->child != NULL) && (node->expanded)) {
+ child_width = tree_get_node_width(node->child);
+ if (width < child_width)
+ width = child_width;
+ }
+ }
+ return width;
}
/**
- * Creates a tree entry for a URL, and links it into the tree
+ * Calculates the height of a node including any children
*
- *
- * \param parent the node to link to
- * \param url the URL (copied)
- * \param data the URL data to use
- * \param title the custom title to use
- * \return the node created, or NULL for failure
+ * \param node the node to calculate the height of
+ * \return the total height of the node and children
*/
-struct node *tree_create_URL_node(struct node *parent,
- const char *url, const struct url_data *data,
- const char *title) {
- struct node *node;
- struct node_element *element;
+int tree_get_node_height(struct node *node) {
+ int y1;
- assert(data);
+ assert(node != NULL);
- node = tree_create_leaf_node(parent, title ? title : url);
- if (!node)
- return NULL;
+ if ((node->child != NULL) && (node->expanded)) {
+ y1 = node->box.y;
+ if (y1 < 0)
+ y1 = 0;
+ node = node->child;
+ while ((node->next != NULL) || ((node->child != NULL) &&
+ (node->expanded))) {
+ for (; node->next != NULL; node = node->next);
+ if ((node->child != NULL) && (node->expanded))
+ node = node->child;
+ }
+ return node->box.y + node->box.height - y1;
+ } else {
+ return node->box.height;
+ }
+}
- element = tree_create_node_element(node, TREE_ELEMENT_THUMBNAIL);
- if (element)
- element->type = NODE_ELEMENT_THUMBNAIL;
- tree_create_node_element(node, TREE_ELEMENT_VISITS);
- tree_create_node_element(node, TREE_ELEMENT_LAST_VISIT);
- element = tree_create_node_element(node, TREE_ELEMENT_URL);
- if (element)
- element->text = strdup(url);
- tree_update_URL_node(node, url, NULL);
- return node;
+/**
+ * Updates the selected state for a region of nodes.
+ *
+ * \param tree the tree to update
+ * \param y the minimum y of the selection rectangle
+ * \param height the height of the selection rectangle
+ * \param invert whether to invert the selected state
+ */
+void tree_handle_selection_area(struct tree *tree, int y, int height,
+ bool invert)
+{
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+
+ if (tree->root->child == NULL)
+ return;
+
+ if (height < 0) {
+ y += height;
+ height = -height;
+ }
+ tree_handle_selection_area_node(tree, tree->root->child, y, height,
+ invert);
}
/**
- * Creates a tree entry for a URL, and links it into the tree.
+ * Updates the selected state for a region of nodes.
*
- * All information is used directly from the url_data, and as such cannot be
- * edited and should never be freed.
- *
- * \param parent the node to link to
- * \param url the URL
- * \param data the URL data to use
- * \return the node created, or NULL for failure
+ * \param tree the tree to update
+ * \param node the node to update children and siblings of
+ * \param y the minimum y of the selection rectangle
+ * \param height the height of the selection rectangle
+ * \param invert whether to invert the selected state
*/
-struct node *tree_create_URL_node_shared(struct node *parent,
- const char *url, const struct url_data *data) {
- struct node *node;
+void tree_handle_selection_area_node(struct tree *tree, struct node *node,
+ int y, int height, bool invert)
+{
+
struct node_element *element;
- const char *title;
+ struct node *update;
+ int y_max;
+ int y0, y1;
- assert(url && data);
+ assert(tree != NULL);
+ assert(node != NULL);
- if (data->title)
- title = data->title;
- else
- title = url;
- node = tree_create_leaf_node_shared(parent, title);
- if (!node)
- return NULL;
+ y_max = y + height;
- element = tree_create_node_element(node, TREE_ELEMENT_THUMBNAIL);
- if (element)
- element->type = NODE_ELEMENT_THUMBNAIL;
- tree_create_node_element(node, TREE_ELEMENT_VISITS);
- tree_create_node_element(node, TREE_ELEMENT_LAST_VISIT);
- element = tree_create_node_element(node, TREE_ELEMENT_URL);
- if (element)
- element->text = url;
+ for (; node != NULL; node = node->next) {
+ if (node->box.y > y_max) return;
+ y0 = node->box.y;
+ y1 = node->box.y + node->box.height;
+ if ((y0 < y_max) && (y1 >= y)) {
+ update = NULL;
+ if (node->expanded) {
+ for (element = &node->data; element != NULL;
+ element = element->next) {
+ y0 = element->box.y;
+ y1 = element->box.y +
+ element->box.height;
+ if ((y0 < y_max) && (y1 >= y)) {
+ update = element->parent;
+ break;
+ }
+ }
+ } else {
+ y0 = node->data.box.y;
+ y1 = node->data.box.y + node->data.box.height;
+ if ((y0 < y_max) && (y1 >= y))
+ update = node->data.parent;
+ }
+ if ((update) && (node != tree->root)) {
+ if (invert) {
+ node->selected = !node->selected;
+ tree_handle_node_element_changed(tree,
+ &node->data);
+ } else if (!node->selected) {
+ node->selected = true;
+ tree_handle_node_element_changed(tree,
+ &node->data);
+ }
+ }
+ }
+ if ((node->child != NULL) && (node->expanded))
+ tree_handle_selection_area_node(tree, node->child, y,
+ height, invert);
+ }
+}
- tree_update_URL_node(node, url, data);
- return node;
+
+/**
+ * Finds a node at a specific location.
+ *
+ * \param root the root node to check from
+ * \param x the x co-ordinate
+ * \param y the y co-ordinate
+ * \param furniture whether the returned area was in an elements furniture
+ * \return the node at the specified position, or NULL for none
+ */
+struct node *tree_get_node_at(struct node *root, int x, int y, bool *furniture)
+{
+ struct node_element *result;
+
+ if ((result = tree_get_node_element_at(root, x, y, furniture)))
+ return result->parent;
+ return NULL;
}
/**
- * Creates a tree entry for a cookie, and links it into the tree.
+ * Finds a node element at a specific location.
*
- * All information is copied from the cookie_data, and as such can
- * be edited and should be freed.
- *
- * \param parent the node to link to
- * \param url the URL
- * \param data the cookie data to use
- * \return the node created, or NULL for failure
+ * \param node the root node to check from
+ * \param x the x co-ordinate
+ * \param y the y co-ordinate
+ * \param furniture whether the returned area was in an elements furniture
+ * \return the node at the specified position, or NULL for none
*/
-struct node *tree_create_cookie_node(struct node *parent,
- const struct cookie_data *data) {
- struct node *node;
+struct node_element *tree_get_node_element_at(struct node *node, int x, int y,
+ bool *furniture)
+{
struct node_element *element;
- char buffer[256];
- char buffer2[16];
+ int x0, x1, y0, y1;
- node = tree_create_leaf_node(parent, data->name);
- if (!node)
- return NULL;
- node->data.data = TREE_ELEMENT_NAME;
- node->editable = false;
+ *furniture = false;
+ for (; node != NULL; node = node->next) {
+ if (node->box.y > y) return NULL;
+ if ((node->box.x - NODE_INSTEP < x) && (node->box.y < y) &&
+ (node->box.x + node->box.width >= x) &&
+ (node->box.y + node->box.height >= y)) {
+ if (node->expanded) {
+ for (element = &node->data; element != NULL;
+ element = element->next) {
+ x0 = element->box.x;
+ y0 = element->box.y;
+ x1 = element->box.x +
+ element->box.width;
+ y1 = element->box.y +
+ element->box.height;
+ if ((x0 < x) && (y0 < y) && (x1 >= x)
+ && (y1 >= y))
+ return element;
+ }
+ } else {
+ x0 = node->data.box.x;
+ y0 = node->data.box.y;
+ x1 = node->data.box.x + node->data.box.width;
+ y1 = node->data.box.y + node->data.box.height;
+ if ((x0 < x) && (y0 < y) && (x1 >= x) &&
+ (y1>= y))
+ return &node->data;
+ }
+ if (((node->child != NULL) ||
+ (node->data.next != NULL)) &&
+ (node->data.box.x - NODE_INSTEP + 4 < x)
+ && (node->data.box.y + 4 < y) &&
+ (node->data.box.x > x) &&
+ (node->data.box.y + 20 > y)) {
+ *furniture = true;
+ return &node->data;
+ }
+ }
+ element = tree_get_node_element_at(node->child, x, y,
+ furniture);
+ if ((node->child != NULL) && (node->expanded) &&
+ (element != NULL))
+ return element;
+ }
+ return NULL;
+}
- element = tree_create_node_element(node, TREE_ELEMENT_PERSISTENT);
- if (element) {
- snprintf(buffer, 256, messages_get("TreePersistent"),
- data->no_destroy ? messages_get("Yes") : messages_get("No"));
- element->text = strdup(buffer);
+
+
+/**
+ * Moves nodes within a tree.
+ *
+ * \param tree the tree to process
+ * \param destination the node to link before/as a child (folders)
+ * or before/after (link)
+ * \param before whether to link siblings before or after the supplied
+ * node
+ */
+void tree_move_selected_nodes(struct tree *tree, struct node *destination,
+ bool before)
+{
+ struct node *link;
+ struct node *test;
+ bool error;
+
+ tree_clear_processing(tree->root);
+ tree_selected_to_processing(tree->root);
+
+ /* the destination node cannot be a child of any node with
+ the processing flag set */
+ error = destination->processing;
+ for (test = destination; test != NULL; test = test->parent)
+ error |= test->processing;
+ if (error) {
+ tree_clear_processing(tree->root);
+ return;
}
- element = tree_create_node_element(node, TREE_ELEMENT_VERSION);
- if (element) {
- snprintf(buffer2, 16, "TreeVersion%i", data->version);
- snprintf(buffer, 256, messages_get("TreeVersion"), messages_get(buffer2));
- element->text = strdup(buffer);
+ if ((destination->folder) && (!destination->expanded) && (!before)) {
+ tree_set_node_expanded(tree, destination, true, false, false);
}
- element = tree_create_node_element(node, TREE_ELEMENT_SECURE);
- if (element) {
- snprintf(buffer, 256, messages_get("TreeSecure"),
- data->secure ? messages_get("Yes") : messages_get("No"));
- element->text = strdup(buffer);
+ link = tree_move_processing_node(tree, tree->root, destination, before,
+ true);
+ while (link != NULL)
+ link = tree_move_processing_node(tree, tree->root, link, false,
+ false);
+
+ tree_clear_processing(tree->root);
+ tree_recalculate_node_positions(tree, tree->root);
+ if (tree->redraw)
+ tree->callbacks->redraw_request(0, 0, tree->width, tree->height,
+ tree->client_data);
+}
+
+
+/**
+ * Sets the processing flag to the selection state.
+ *
+ * \param node the node to process siblings and children of
+ */
+void tree_selected_to_processing(struct node *node)
+{
+ for (; node != NULL; node = node->next) {
+ node->processing = node->selected;
+ if ((node->child != NULL) && (node->expanded))
+ tree_selected_to_processing(node->child);
}
- element = tree_create_node_element(node, TREE_ELEMENT_LAST_USED);
- if (element) {
- snprintf(buffer, 256, messages_get("TreeLastUsed"),
- (data->last_used > 0) ?
- ctime(&data->last_used) : messages_get("TreeUnknown"));
- if (data->last_used > 0)
- buffer[strlen(buffer) - 1] = '\0';
- element->text = strdup(buffer);
+}
+
+
+/**
+ * Clears the processing flag.
+ *
+ * \param node the node to process siblings and children of
+ */
+void tree_clear_processing(struct node *node)
+{
+ for (; node != NULL; node = node->next) {
+ node->processing = false;
+ if (node->child != NULL)
+ tree_clear_processing(node->child);
}
- element = tree_create_node_element(node, TREE_ELEMENT_EXPIRES);
- if (element) {
- snprintf(buffer, 256, messages_get("TreeExpires"),
- (data->expires > 0)
- ? (data->expires == 1)
- ? messages_get("TreeSession")
- : ctime(&data->expires)
- : messages_get("TreeUnknown"));
- if (data->expires > 0 && data->expires != 1)
- buffer[strlen(buffer) - 1] = '\0';
- element->text = strdup(buffer);
- }
- element = tree_create_node_element(node, TREE_ELEMENT_PATH);
- if (element) {
- snprintf(buffer, 256, messages_get("TreePath"), data->path,
- data->path_from_set ? messages_get("TreeHeaders") : "");
- element->text = strdup(buffer);
- }
- element = tree_create_node_element(node, TREE_ELEMENT_DOMAIN);
- if (element) {
- snprintf(buffer, 256, messages_get("TreeDomain"), data->domain,
- data->domain_from_set ? messages_get("TreeHeaders") : "");
- element->text = strdup(buffer);
- }
- if ((data->comment) && (strcmp(data->comment, ""))) {
- element = tree_create_node_element(node, TREE_ELEMENT_COMMENT);
- if (element) {
- snprintf(buffer, 256, messages_get("TreeComment"), data->comment);
- element->text = strdup(buffer);
- }
- }
- element = tree_create_node_element(node, TREE_ELEMENT_VALUE);
- if (element) {
- snprintf(buffer, 256, messages_get("TreeValue"),
- data->value ? data->value : messages_get("TreeUnused"));
- element->text = strdup(buffer);
- }
-
- tree_set_node_sprite(node, "small_xxx", "small_xxx");
- return node;
}
/**
- * Creates an empty text node element and links it to a node.
+ * Moves the first node in a tree with the processing flag set.
*
- * \param parent the parent node
- * \param user_type the required user_type
- * \return the newly created element.
+ * \param tree the tree in which the move takes place
+ * \param node the node to move siblings/children of
+ * \param link the node to link before/as a child (folders) or before/after
+ * (link)
+ * \param before whether to link siblings before or after the supplied node
+ * \param first whether to always link after the supplied node (ie not
+ * inside of folders)
+ * \return the node moved
*/
-struct node_element *tree_create_node_element(struct node *parent, node_element_data data) {
- struct node_element *element;
+struct node *tree_move_processing_node(struct tree *tree, struct node *node,
+ struct node *link, bool before, bool first)
+{
+ struct node *result;
- element = calloc(sizeof(struct node_element), 1);
- if (!element) return NULL;
- element->parent = parent;
- element->data = data;
- element->type = NODE_ELEMENT_TEXT;
- element->next = parent->data.next;
- parent->data.next = element;
- return element;
+ bool folder = link->folder;
+ for (; node != NULL; node = node->next) {
+ if (node->processing) {
+ node->processing = false;
+ tree_delink_node(tree, node);
+ if (!first)
+ link->folder = false;
+ tree_link_node(tree, link, node, before);
+ if (!first)
+ link->folder = folder;
+ return node;
+ }
+ if (node->child != NULL) {
+ result = tree_move_processing_node(tree, node->child,
+ link, before, first);
+ if (result != NULL)
+ return result;
+ }
+ }
+ return NULL;
}
/**
- * Recalculates the size of a tree.
+ * Starts editing a node_element
*
- * \param tree the tree to recalculate
+ * \param tree The tree to which element belongs
+ * \param element The element to start being edited
*/
-void tree_recalculate_size(struct tree *tree) {
+void tree_start_edit(struct tree *tree, struct node_element *element)
+{
+ struct node *parent;
int width, height;
- assert(tree);
+ assert(tree != NULL);
+ assert(element != NULL);
- if (!tree->handle)
+ if (tree->editing != NULL)
+ tree_stop_edit(tree, true);
+
+ parent = element->parent;
+ if (&parent->data == element)
+ parent = parent->parent;
+ for (; parent != NULL; parent = parent->parent) {
+ if (!parent->expanded) {
+ tree_set_node_expanded(tree, parent, true,
+ false, false);
+ }
+ }
+
+ tree->editing = element;
+ tree->callbacks->get_window_dimensions(&width, NULL, tree->client_data);
+ width -= element->box.x;
+ height = element->box.height;
+ if (element->type == NODE_ELEMENT_TEXT_PLUS_ICON)
+ width -= NODE_INSTEP;
+
+ tree->textarea = textarea_create(width, height, 0,
+ &plot_fstyle, tree_textarea_redraw_request,
+ tree);
+ if (tree->textarea == NULL) {
+ tree_stop_edit(tree, false);
return;
- width = tree->width;
- height = tree->height;
- if (tree->root) {
- tree->width = tree_get_node_width(tree->root);
- tree->height = tree_get_node_height(tree->root);
- } else {
- tree->width = 0;
- tree->height = 0;
}
- if ((width != tree->width) || (height != tree->height))
- tree_resized(tree);
+ textarea_set_text(tree->textarea, element->text);
+
+ tree_handle_node_element_changed(tree, element);
+ tree_recalculate_size(tree);
+ tree->callbacks->scroll_visible(element->box.y, element->box.height,
+ tree->client_data);
}
/**
- * Returns the selected node, or NULL if multiple nodes are selected.
+ * Stops editing a node_element
*
- * \param node the node to search sibling and children
- * \return the selected node, or NULL if multiple nodes are selected
+ * \param tree The tree to stop editing for
+ * \param keep_changes If true the changes made to the text will be kept,
+ * if false they will be dropped
*/
-struct node *tree_get_selected_node(struct node *node) {
- struct node *result = NULL;
- struct node *temp;
+void tree_stop_edit(struct tree *tree, bool keep_changes)
+{
+ int text_len;
+ char *text = NULL;
+ struct node_element *element;
+ struct node_msg_data msg_data;
+ node_callback_resp response;
- for (; node; node = node->next) {
- if (node->selected) {
- if (result)
- return NULL;
- result = node;
+ assert(tree != NULL);
+
+ if (tree->editing == NULL || tree->textarea == NULL)
+ return;
+
+ element = tree->editing;
+
+ if (keep_changes) {
+ text_len = textarea_get_text(tree->textarea, NULL, 0);
+ text = malloc(text_len * sizeof(char));
+ if (text == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ textarea_destroy(tree->textarea);
+ tree->textarea = NULL;
+ return;
}
- if ((node->child) && (node->expanded)) {
- temp = tree_get_selected_node(node->child);
- if (temp) {
- if (result)
- return NULL;
- else
- result = temp;
- }
+ textarea_get_text(tree->textarea, text, text_len);
+ }
+
+
+ if (keep_changes && element->parent->user_callback != NULL) {
+ msg_data.msg = NODE_ELEMENT_EDIT_FINISHING;
+ msg_data.flag = element->flag;
+ msg_data.node = element->parent;
+ msg_data.data.text = text;
+ response = element->parent->user_callback(
+ element->parent->callback_data,
+ &msg_data);
+
+ switch (response) {
+ case NODE_CALLBACK_REJECT:
+ free(text);
+ text = NULL;
+ break;
+ case NODE_CALLBACK_CONTINUE:
+ free(text);
+ text = NULL;
+ return;
+ case NODE_CALLBACK_HANDLED:
+ case NODE_CALLBACK_NOT_HANDLED:
+ text = msg_data.data.text;
+ break;
}
}
- return result;
+
+ textarea_destroy(tree->textarea);
+ tree->textarea = NULL;
+ tree->editing = NULL;
+
+ if (text != NULL)
+ tree_update_node_element(tree, element, text, NULL);
+ else
+ tree_handle_node_element_changed(tree, element);
+
+
+ tree_recalculate_size(tree);
+ if (element->parent->user_callback != NULL) {
+ msg_data.msg = NODE_ELEMENT_EDIT_FINISHED;
+ msg_data.flag = element->flag;
+ msg_data.node = element->parent;
+ element->parent->user_callback(element->parent->callback_data,
+ &msg_data);
+ }
}
+
+/**
+ * Tree utility function. Placed here so that this code doesn't have to be
+ * copied by each user.
+ *
+ * \param name the name of the loaded icon, if it's not a full path the icon is
+ * looked for in the directory specified by option_tree_icons_dir
+ * \return the icon in form of a content or NULL on failure
+ */
+hlcache_handle *tree_load_icon(const char *name)
+{
+ char *url = NULL;
+ const char *icon_url = NULL;
+ int len;
+ hlcache_handle *c;
+
+ /* TODO: something like bitmap_from_disc is needed here */
+
+ if (!strncmp(name, "file://", 7)) {
+ icon_url = name;
+ } else {
+ char *native_path;
+
+ if (option_tree_icons_dir == NULL)
+ return NULL;
+
+ /* path + separator + leafname + '\0' */
+ len = strlen(option_tree_icons_dir) + 1 + strlen(name) + 1;
+ native_path = malloc(len);
+ if (native_path == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+
+ /* Build native path */
+ memcpy(native_path, option_tree_icons_dir,
+ strlen(option_tree_icons_dir) + 1);
+ path_add_part(native_path, len, name);
+
+ /* Convert native path to URL */
+ url = path_to_url(native_path);
+
+ free(native_path);
+ icon_url = url;
+ }
+
+ /* Fetch the icon */
+ hlcache_handle_retrieve(icon_url, 0, 0, 0,
+ tree_icon_callback, 0, 0, 0, &c);
+
+ /* If we built the URL here, free it */
+ if (url != NULL)
+ free(url);
+
+ return c;
+}
+
+
+/**
+ * Callback for fetchcache(). Should be removed once bitmaps get loaded directly
+ * from disc
+ */
+nserror tree_icon_callback(hlcache_handle *handle,
+ const hlcache_event *event, void *pw)
+{
+ return NSERROR_OK;
+}
+
+/**
+ * Redraw requests from the textarea are piped through this because we have to
+ * check the redraw flag of the tree before requesting a redraw and change the
+ * position to tree origin relative.
+ */
+void tree_textarea_redraw_request(void *data, int x, int y,
+ int width, int height)
+{
+ struct tree *tree = data;
+ x = x + tree->editing->box.x;
+ y = y + tree->editing->box.y;
+ if (tree->editing->type == NODE_ELEMENT_TEXT_PLUS_ICON)
+ x += NODE_INSTEP;
+
+ if (tree->redraw)
+ tree->callbacks->redraw_request(x, y,
+ width, height,
+ tree->client_data);
+}
Index: desktop/cookies.h
===================================================================
--- desktop/cookies.h (revision 10834)
+++ desktop/cookies.h (working copy)
@@ -25,8 +25,25 @@
#include <stdbool.h>
+#include "desktop/tree.h"
+
struct cookie_data;
-bool cookies_update(const char *domain, const struct cookie_data *data);
+bool cookies_initialise(struct tree *tree);
+unsigned int cookies_get_tree_flags(void);
+bool cookies_update(const struct cookie_data *data);
+void cookies_delete(const struct cookie_data *data);
+void cookies_cleanup(void);
+void cookies_delete_selected(void);
+void cookies_delete_all(void);
+void cookies_select_all(void);
+void cookies_clear_selection(void);
+void cookies_expand_all(void);
+void cookies_expand_domains(void);
+void cookies_expand_cookies(void);
+void cookies_collapse_all(void);
+void cookies_collapse_domains(void);
+void cookies_collapse_cookies(void);
+
#endif
Index: desktop/tree.h
===================================================================
--- desktop/tree.h (revision 10834)
+++ desktop/tree.h (working copy)
@@ -1,5 +1,6 @@
/*
* Copyright 2004 Richard Wilson <not_ginger_matt(a)users.sourceforge.net>
+ * Copyright 2009 Paul Blokus <paul_pl(a)users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -26,157 +27,156 @@
#include <stdbool.h>
#include <stdint.h>
-struct url_data;
-struct cookie_data;
+#include "desktop/browser.h"
+#include "image/bitmap.h"
-typedef enum {
- TREE_ELEMENT_URL,
- TREE_ELEMENT_ADDED,
- TREE_ELEMENT_LAST_VISIT,
- TREE_ELEMENT_VISITS,
- TREE_ELEMENT_VISITED,
- TREE_ELEMENT_THUMBNAIL,
- TREE_ELEMENT_TITLE,
- TREE_ELEMENT_NAME,
- TREE_ELEMENT_VALUE,
- TREE_ELEMENT_COMMENT,
- TREE_ELEMENT_DOMAIN,
- TREE_ELEMENT_PATH,
- TREE_ELEMENT_EXPIRES,
- TREE_ELEMENT_LAST_USED,
- TREE_ELEMENT_SECURE,
- TREE_ELEMENT_VERSION,
- TREE_ELEMENT_PERSISTENT,
- TREE_ELEMENT_SSL
-} node_element_data;
+struct hlcache_handle;
-#define NODE_INSTEP 40
+/* Tree flags */
+#define TREE_NO_FLAGS 0
+#define TREE_NO_DRAGS 1
+#define TREE_NO_FURNITURE 2
+#define TREE_SINGLE_SELECT 4
+#define TREE_NO_SELECT 8
+#define TREE_MOVABLE 16
+/* if the last child of a directory is deleted the directory will be deleted
+ too */
+#define TREE_DELETE_EMPTY_DIRS 16
-struct node_sprite;
-struct toolbar;
+/* the flag for the first node_element in every node, all other flags should
+ be different than this one */
+#define TREE_ELEMENT_TITLE 0x00
+/* these should be defined in front end code */
+extern const char tree_directory_icon_name[];
+extern const char tree_content_icon_name[];
+
+struct tree;
+struct node;
+struct node_element;
+
typedef enum {
- NODE_ELEMENT_TEXT, /* <-- Text only */
- NODE_ELEMENT_TEXT_PLUS_SPRITE, /* <-- Text and sprite */
- NODE_ELEMENT_THUMBNAIL, /* <-- Bitmap only */
+ NODE_ELEMENT_TEXT, /* Text only */
+ NODE_ELEMENT_TEXT_PLUS_ICON, /* Text and icon */
+ NODE_ELEMENT_BITMAP /* Bitmap only */
} node_element_type;
+typedef enum {
+ NODE_DELETE_ELEMENT_TXT, /* The text of an element of the node
+ is being deleted */
+ NODE_DELETE_ELEMENT_IMG, /* The bitmap or icon of a node is being
+ deleted */
+ NODE_LAUNCH, /* The node has been launched */
+ NODE_ELEMENT_EDIT_FINISHING, /* New text has to be accepted or
+ rejected */
+ NODE_ELEMENT_EDIT_FINISHED /* Editing of a node_element has been
+ finished */
+} node_msg;
-struct node_element_box {
- int x; /* <-- X offset from origin */
- int y; /* <-- Y offset from origin */
- int width; /* <-- Element width */
- int height; /* <-- Element height */
+typedef enum {
+ NODE_CALLBACK_HANDLED,
+ NODE_CALLBACK_NOT_HANDLED,
+ NODE_CALLBACK_REJECT, /* reject new text for node element and
+ leave editing mode */
+ NODE_CALLBACK_CONTINUE /* don't leave editig mode */
+} node_callback_resp;
+
+struct node_msg_data {
+ node_msg msg;
+ unsigned int flag;
+ struct node *node;
+ union {
+ char *text;
+ void *bitmap;
+ } data;
};
-
-struct node_element {
- struct node *parent; /* <-- Parent node */
- node_element_type type; /* <-- Element type */
- struct node_element_box box; /* <-- Element bounding box */
- const char *text; /* <-- Text for the element */
- struct node_sprite *sprite; /* <-- Sprite for the element */
- struct node_element *next; /* <-- Next node element */
- node_element_data data; /* <-- Data being represented */
+struct treeview_table {
+ void (*redraw_request)(int x, int y, int width, int height,
+ void *data);
+ void (*resized)(struct tree *tree, int width, int height,
+ void *data);
+ void (*scroll_visible)(int y, int height, void *data);
+ void (*get_window_dimensions)(int *width, int *height, void *data);
};
+/**
+ * Informs the client about any events requiring his action
+ *
+ * \param user_data the user data which was passed at tree creation
+ * \param msg_data structure containing all the message information
+ * \return the appropriate node_callback_resp response
+ */
+typedef node_callback_resp (*tree_node_user_callback)(void *user_data,
+ struct node_msg_data *msg_data);
-struct node {
- bool selected; /* <-- Whether the node is selected */
- bool expanded; /* <-- Whether the node is expanded */
- bool folder; /* <-- Whether the node is a folder */
- bool editable; /* <-- Whether the node is editable */
- bool retain_in_memory; /* <-- Whether the node remains in memory after deletion */
- bool deleted; /* <-- Whether the node is currently deleted */
- bool processing; /* <-- Internal flag used when moving */
- struct node_element_box box; /* <-- Bounding box of all elements */
- struct node_element data; /* <-- Data to display */
- struct node *parent; /* <-- Parent entry (NULL for root) */
- struct node *child; /* <-- First child */
- struct node *last_child; /* <-- Last child */
- struct node *previous; /* <-- Previous child of the parent */
- struct node *next; /* <-- Next child of the parent */
+/* Non-platform specific code */
-};
+/* Functions for creating/deleting tree primitives and for tree structure
+ manipulation */
+struct tree *tree_create(unsigned int flags,
+ const struct treeview_table *callbacks,
+ void *client_data);
+struct node *tree_create_folder_node(struct tree *tree, struct node *parent,
+ const char *title, bool editable, bool retain_in_memory,
+ bool deleted);
+struct node *tree_create_leaf_node(struct tree *tree, struct node *parent,
+ const char *title, bool editable, bool retain_in_memory,
+ bool deleted);
+struct node_element *tree_create_node_element(struct node *parent,
+ node_element_type type, unsigned int flag, bool editable);
+void tree_link_node(struct tree *tree, struct node *link, struct node *node,
+ bool before);
+void tree_delink_node(struct tree *tree, struct node *node);
+void tree_delete(struct tree *tree);
+void tree_delete_node(struct tree *tree, struct node *node, bool siblings);
-struct tree {
- unsigned int handle; /* <-- User assigned handle */
- int offset_x; /* <-- User assigned tree x offset */
- int offset_y; /* <-- User assigned tree y offset */
- struct node *root; /* <-- Tree root element */
- int width; /* <-- Tree width */
- int height; /* <-- Tree height */
- int window_width; /* <-- Tree window width */
- int window_height; /* <-- Tree window height */
- bool no_drag; /* <-- Tree items can't be dragged out */
- bool no_vscroll; /* <-- Tree has a vertical scroll only when needed */
- bool no_furniture; /* <-- Tree does not have connecting lines */
- bool single_selection; /* <-- There can only be one item selected */
- int edit_handle; /* <-- Handle for editing information */
- uintptr_t textarea_handle; /* <-- Handle for UTF-8 textarea */
- bool movable; /* <-- Whether nodes can be moved */
- struct node_element *editing; /* <-- Node element being edited */
- struct node *temp_selection; /* <-- Temporarily selected node */
- struct toolbar *toolbar; /* <-- Tree toolbar */
-};
+/* setters and getters for properties and data */
+void tree_set_node_icon(struct tree *tree, struct node *node,
+ struct hlcache_handle *icon);
+void tree_set_node_expanded(struct tree *tree, struct node *node, bool expanded,
+ bool folder, bool leaf);
+void tree_set_node_selected(struct tree *tree, struct node *node, bool all,
+ bool selected);
+void tree_set_node_sort_function(struct tree *tree, struct node *node,
+ int (*sort) (struct node *, struct node *));
+void tree_set_node_user_callback(struct node *node,
+ tree_node_user_callback callback, void *data);
+void tree_set_redraw(struct tree *tree, bool redraw);
+bool tree_get_redraw(struct tree *tree);
+bool tree_node_has_selection(struct node *node);
+bool tree_node_is_deleted(struct node *node);
+bool tree_node_is_folder(struct node *node);
+void tree_update_node_element(struct tree *tree, struct node_element *element,
+ const char *text, void *bitmap);
+const char *tree_node_element_get_text(struct node_element *element);
+struct node *tree_get_root(struct tree *tree);
+bool tree_is_edited(struct tree *tree);
-/* Non-platform specific code */
-void tree_initialise(struct tree *tree);
-void tree_initialise_nodes(struct tree *tree, struct node *root);
-void tree_handle_node_changed(struct tree *tree, struct node *node,
- bool recalculate_sizes, bool expansion);
-void tree_handle_node_element_changed(struct tree *tree,
- struct node_element *element);
-void tree_recalculate_node(struct tree *tree, struct node *node, bool recalculate_sizes);
-void tree_recalculate_node_positions(struct tree *tree, struct node *root);
-struct node *tree_get_node_at(struct node *root, int x, int y, bool *furniture);
-struct node_element *tree_get_node_element_at(struct node *node, int x, int y,
- bool *furniture);
-struct node_element *tree_find_element(struct node *node, node_element_data data);
-void tree_move_selected_nodes(struct tree *tree, struct node *destination,
- bool before);
-bool tree_has_selection(struct node *node);
-void tree_draw(struct tree *tree, int clip_x, int clip_y, int clip_width,
- int clip_height);
-void tree_link_node(struct node *link, struct node *node, bool before);
-void tree_delink_node(struct node *node);
-struct node *tree_create_folder_node(struct node *parent, const char *title);
-struct node *tree_create_leaf_node(struct node *parent, const char *title);
-struct node *tree_create_URL_node(struct node *parent,
- const char *url, const struct url_data *data,
- const char *title);
-struct node *tree_create_URL_node_shared(struct node *parent,
- const char *url, const struct url_data *data);
-struct node *tree_create_cookie_node(struct node *parent,
- const struct cookie_data *data);
-void tree_set_node_sprite(struct node *node, const char *sprite,
- const char *expanded);
-void tree_set_node_expanded(struct tree *tree, struct node *node, bool expanded);
-void tree_set_node_selected(struct tree *tree, struct node *node,
- bool selected);
-void tree_handle_selection_area(struct tree *tree, int x, int y, int width,
- int height, bool invert);
+/* functions for traversing the tree */
+struct node *tree_node_get_child(struct node *node);
+struct node *tree_node_get_next(struct node *node);
+
+void tree_draw(struct tree *tree, int x, int y,
+ int clip_x, int clip_y, int clip_width, int clip_height);
+
+struct node_element *tree_node_find_element(struct node *node,
+ unsigned int flag, struct node_element *after);
void tree_delete_selected_nodes(struct tree *tree, struct node *node);
-void tree_delete_node(struct tree *tree, struct node *node, bool siblings);
-void tree_recalculate_size(struct tree *tree);
-bool tree_handle_expansion(struct tree *tree, struct node *node, bool expanded,
- bool folder, bool leaf);
struct node *tree_get_selected_node(struct node *node);
struct node *tree_get_link_details(struct tree *tree, int x, int y,
bool *before);
+void tree_launch_selected(struct tree *tree);
-
-/* Platform specific code */
-void tree_initialise_redraw(struct tree *tree);
-void tree_redraw_area(struct tree *tree, int x, int y, int width, int height);
-void tree_draw_line(int x, int y, int width, int height);
-void tree_draw_node_element(struct tree *tree, struct node_element *element);
-void tree_draw_node_expansion(struct tree *tree, struct node *node);
-void tree_recalculate_node_element(struct node_element *element);
-void tree_update_URL_node(struct node *node, const char *url,
- const struct url_data *data);
-void tree_resized(struct tree *tree);
-void tree_set_node_sprite_folder(struct node *node);
-
+bool tree_mouse_action(struct tree *tree, browser_mouse_state mouse,
+ int x, int y);
+void tree_drag_end(struct tree *tree, browser_mouse_state mouse, int x0, int y0,
+ int x1, int y1);
+bool tree_keypress(struct tree *tree, uint32_t key);
+
+int tree_alphabetical_sort(struct node *, struct node *);
+void tree_start_edit(struct tree *tree, struct node_element *element);
+struct hlcache_handle *tree_load_icon(const char *name);
+
#endif
Index: desktop/options.c
===================================================================
--- desktop/options.c (revision 10834)
+++ desktop/options.c (working copy)
@@ -31,16 +31,10 @@
#include <stdio.h>
#include <string.h>
#include <strings.h>
-#include <libxml/HTMLparser.h>
-#include <libxml/HTMLtree.h>
-#include "content/urldb.h"
#include "css/css.h"
#include "desktop/options.h"
#include "desktop/plot_style.h"
-#include "desktop/tree.h"
#include "utils/log.h"
-#include "utils/messages.h"
-#include "utils/url.h"
#include "utils/utils.h"
#if defined(riscos)
@@ -145,6 +139,7 @@
#else
unsigned int option_min_reflow_period = 25; /* time in cs */
#endif
+char *option_tree_icons_dir = NULL;
bool option_core_select_menu = false;
/** top margin of exported page*/
int option_margin_top = DEFAULT_MARGIN_TOP_MM;
@@ -247,6 +242,7 @@
{ "scale", OPTION_INTEGER, &option_scale },
{ "incremental_reflow", OPTION_BOOL, &option_incremental_reflow },
{ "min_reflow_period", OPTION_INTEGER, &option_min_reflow_period },
+ { "tree_icons_dir", OPTION_STRING, &option_tree_icons_dir },
{ "core_select_menu", OPTION_BOOL, &option_core_select_menu },
/* Fetcher options */
{ "max_fetchers", OPTION_INTEGER, &option_max_fetchers },
@@ -276,13 +272,6 @@
#define option_table_entries (sizeof option_table / sizeof option_table[0])
-static void options_load_tree_directory(xmlNode *ul, struct node *directory);
-static void options_load_tree_entry(xmlNode *li, struct node *directory);
-xmlNode *options_find_tree_element(xmlNode *node, const char *name);
-bool options_save_tree_directory(struct node *directory, xmlNode *node);
-bool options_save_tree_entry(struct node *entry, xmlNode *node);
-
-
/**
* Read options from a file.
*
@@ -429,351 +418,3 @@
fprintf(stderr, "\n");
}
}
-
-/**
- * Loads a hotlist as a tree from a specified file.
- *
- * \param filename name of file to read
- * \return the hotlist file represented as a tree, or NULL on failure
- */
-struct tree *options_load_tree(const char *filename) {
- xmlDoc *doc;
- xmlNode *html, *body, *ul;
- struct tree *tree;
-
- doc = htmlParseFile(filename, "iso-8859-1");
- if (!doc) {
- warn_user("HotlistLoadError", messages_get("ParsingFail"));
- return NULL;
- }
-
- html = options_find_tree_element((xmlNode *) doc, "html");
- body = options_find_tree_element(html, "body");
- ul = options_find_tree_element(body, "ul");
- if (!ul) {
- xmlFreeDoc(doc);
- warn_user("HotlistLoadError",
- "(<html>...<body>...<ul> not found.)");
- return NULL;
- }
-
- tree = calloc(sizeof(struct tree), 1);
- if (!tree) {
- xmlFreeDoc(doc);
- warn_user("NoMemory", 0);
- return NULL;
- }
- tree->root = tree_create_folder_node(NULL, "Root");
- if (!tree->root) {
- free(tree);
- xmlFreeDoc(doc);
-
- return NULL;
- }
-
- options_load_tree_directory(ul, tree->root);
- tree->root->expanded = true;
- tree_initialise(tree);
-
- xmlFreeDoc(doc);
- return tree;
-}
-
-
-/**
- * Parse a directory represented as a ul.
- *
- * \param ul xmlNode for parsed ul
- * \param directory directory to add this directory to
- */
-void options_load_tree_directory(xmlNode *ul, struct node *directory) {
- char *title;
- struct node *dir;
- xmlNode *n;
-
- assert(ul);
- assert(directory);
-
- for (n = ul->children; n; n = n->next) {
- /* The ul may contain entries as a li, or directories as
- * an h4 followed by a ul. Non-element nodes may be present
- * (eg. text, comments), and are ignored. */
-
- if (n->type != XML_ELEMENT_NODE)
- continue;
-
- if (strcmp((const char *) n->name, "li") == 0) {
- /* entry */
- options_load_tree_entry(n, directory);
-
- } else if (strcmp((const char *) n->name, "h4") == 0) {
- /* directory */
- title = (char *) xmlNodeGetContent(n);
- if (!title) {
- warn_user("HotlistLoadError", "(Empty <h4> "
- "or memory exhausted.)");
- return;
- }
-
- for (n = n->next;
- n && n->type != XML_ELEMENT_NODE;
- n = n->next)
- ;
- if (!n || strcmp((const char *) n->name, "ul") != 0) {
- /* next element isn't expected ul */
- free(title);
- warn_user("HotlistLoadError", "(Expected "
- "<ul> not present.)");
- return;
- }
-
- dir = tree_create_folder_node(directory, title);
- if (!dir) {
- free(title);
-
- return;
- }
- options_load_tree_directory(n, dir);
- }
- }
-}
-
-
-/**
- * Parse an entry represented as a li.
- *
- * \param li xmlNode for parsed li
- * \param directory directory to add this entry to
- */
-void options_load_tree_entry(xmlNode *li, struct node *directory) {
- char *url = NULL, *url1 = NULL;
- char *title = NULL;
- struct node *entry;
- xmlNode *n;
- const struct url_data *data;
- url_func_result res;
-
- for (n = li->children; n; n = n->next) {
- /* The li must contain an "a" element */
- if (n->type == XML_ELEMENT_NODE &&
- strcmp((const char *) n->name, "a") == 0) {
- url1 = (char *) xmlGetProp(n, (const xmlChar *) "href");
- title = (char *) xmlNodeGetContent(n);
- }
- }
-
- if (!url1 || !title) {
- warn_user("HotlistLoadError", "(Missing <a> in <li> or "
- "memory exhausted.)");
- return;
- }
-
- /* We're loading external input.
- * This may be garbage, so attempt to normalise
- */
- res = url_normalize(url1, &url);
- if (res != URL_FUNC_OK) {
- LOG(("Failed normalising '%s'", url1));
-
- if (res == URL_FUNC_NOMEM)
- warn_user("NoMemory", NULL);
-
- xmlFree(url1);
- xmlFree(title);
-
- return;
- }
-
- /* No longer need this */
- xmlFree(url1);
-
- data = urldb_get_url_data(url);
- if (!data) {
- /* No entry in database, so add one */
- urldb_add_url(url);
- /* now attempt to get url data */
- data = urldb_get_url_data(url);
- }
- if (!data) {
- xmlFree(title);
- free(url);
-
- return;
- }
-
- /* Make this URL persistent */
- urldb_set_url_persistence(url, true);
-
- if (!data->title)
- urldb_set_url_title(url, title);
-
- entry = tree_create_URL_node(directory, url, data, title);
- if (entry == NULL) {
- /** \todo why isn't this fatal? */
- warn_user("NoMemory", 0);
- }
-
- xmlFree(title);
- free(url);
-}
-
-
-/**
- * Search the children of an xmlNode for an element.
- *
- * \param node xmlNode to search children of, or 0
- * \param name name of element to find
- * \return first child of node which is an element and matches name, or
- * 0 if not found or parameter node is 0
- */
-xmlNode *options_find_tree_element(xmlNode *node, const char *name) {
- xmlNode *n;
- if (!node)
- return 0;
- for (n = node->children;
- n && !(n->type == XML_ELEMENT_NODE &&
- strcmp((const char *) n->name, name) == 0);
- n = n->next)
- ;
- return n;
-}
-
-
-/**
- * Perform a save to a specified file
- *
- * /param filename the file to save to
- */
-bool options_save_tree(struct tree *tree, const char *filename, const char *page_title) {
- int res;
- xmlDoc *doc;
- xmlNode *html, *head, *title, *body;
-
- /* Unfortunately the Browse Hotlist format is invalid HTML,
- * so this is a lie. */
- doc = htmlNewDoc(
- (const xmlChar *) "http://www.w3.org/TR/html4/strict.dtd",
- (const xmlChar *) "-//W3C//DTD HTML 4.01//EN");
- if (!doc) {
- warn_user("NoMemory", 0);
- return false;
- }
-
- html = xmlNewNode(NULL, (const xmlChar *) "html");
- if (!html) {
- warn_user("NoMemory", 0);
- xmlFreeDoc(doc);
- return false;
- }
- xmlDocSetRootElement(doc, html);
-
- head = xmlNewChild(html, NULL, (const xmlChar *) "head", NULL);
- if (!head) {
- warn_user("NoMemory", 0);
- xmlFreeDoc(doc);
- return false;
- }
-
- title = xmlNewTextChild(head, NULL, (const xmlChar *) "title",
- (const xmlChar *) page_title);
- if (!title) {
- warn_user("NoMemory", 0);
- xmlFreeDoc(doc);
- return false;
- }
-
- body = xmlNewChild(html, NULL, (const xmlChar *) "body", NULL);
- if (!body) {
- warn_user("NoMemory", 0);
- xmlFreeDoc(doc);
- return false;
- }
-
- if (!options_save_tree_directory(tree->root, body)) {
- warn_user("NoMemory", 0);
- xmlFreeDoc(doc);
- return false;
- }
-
- doc->charset = XML_CHAR_ENCODING_UTF8;
- res = htmlSaveFileEnc(filename, doc, "iso-8859-1");
- if (res == -1) {
- warn_user("HotlistSaveError", 0);
- xmlFreeDoc(doc);
- return false;
- }
-
- xmlFreeDoc(doc);
- return true;
-}
-
-
-/**
- * Add a directory to the HTML tree for saving.
- *
- * \param directory hotlist directory to add
- * \param node node to add ul to
- * \return true on success, false on memory exhaustion
- */
-bool options_save_tree_directory(struct node *directory, xmlNode *node) {
- struct node *child;
- xmlNode *ul, *h4;
-
- ul = xmlNewChild(node, NULL, (const xmlChar *) "ul", NULL);
- if (!ul)
- return false;
-
- for (child = directory->child; child; child = child->next) {
- if (!child->folder) {
- /* entry */
- if (!options_save_tree_entry(child, ul))
- return false;
- } else {
- /* directory */
- /* invalid HTML */
- h4 = xmlNewTextChild(ul, NULL,
- (const xmlChar *) "h4",
- (const xmlChar *) child->data.text);
- if (!h4)
- return false;
-
- if (!options_save_tree_directory(child, ul))
- return false;
- } }
-
- return true;
-}
-
-
-/**
- * Add an entry to the HTML tree for saving.
- *
- * The node must contain a sequence of node_elements in the following order:
- *
- * \param entry hotlist entry to add
- * \param node node to add li to
- * \return true on success, false on memory exhaustion
- */
-bool options_save_tree_entry(struct node *entry, xmlNode *node) {
- xmlNode *li, *a;
- xmlAttr *href;
- struct node_element *element;
-
- li = xmlNewChild(node, NULL, (const xmlChar *) "li", NULL);
- if (!li)
- return false;
-
- a = xmlNewTextChild(li, NULL, (const xmlChar *) "a",
- (const xmlChar *) entry->data.text);
- if (!a)
- return false;
-
- element = tree_find_element(entry, TREE_ELEMENT_URL);
- if (!element)
- return false;
- href = xmlNewProp(a, (const xmlChar *) "href",
- (const xmlChar *) element->text);
- if (!href)
- return false;
- return true;
-}
Index: content/urldb.c
===================================================================
--- content/urldb.c (revision 10834)
+++ content/urldb.c (working copy)
@@ -245,13 +245,11 @@
static bool urldb_iterate_entries_host(struct search_node *parent,
bool (*url_callback)(const char *url,
const struct url_data *data),
- bool (*cookie_callback)(const char *domain,
- const struct cookie_data *data));
+ bool (*cookie_callback)(const struct cookie_data *data));
static bool urldb_iterate_entries_path(const struct path_data *parent,
bool (*url_callback)(const char *url,
const struct url_data *data),
- bool (*cookie_callback)(const char *domain,
- const struct cookie_data *data));
+ bool (*cookie_callback)(const struct cookie_data *data));
/* Insertion */
static struct host_part *urldb_add_host_node(const char *part,
@@ -1390,8 +1388,7 @@
*
* \param callback Function to callback for each entry
*/
-void urldb_iterate_cookies(bool (*callback)(const char *domain,
- const struct cookie_data *data))
+void urldb_iterate_cookies(bool (*callback)(const struct cookie_data *data))
{
int i;
@@ -1415,8 +1412,7 @@
bool urldb_iterate_entries_host(struct search_node *parent,
bool (*url_callback)(const char *url,
const struct url_data *data),
- bool (*cookie_callback)(const char *domain,
- const struct cookie_data *data))
+ bool (*cookie_callback)(const struct cookie_data *data))
{
if (parent == &empty)
return true;
@@ -1452,11 +1448,11 @@
bool urldb_iterate_entries_path(const struct path_data *parent,
bool (*url_callback)(const char *url,
const struct url_data *data),
- bool (*cookie_callback)(const char *domain,
- const struct cookie_data *data))
+ bool (*cookie_callback)(const struct cookie_data *data))
{
const struct path_data *p = parent;
-
+ const struct cookie_data *c;
+
do {
if (p->children != NULL) {
/* Drill down into children */
@@ -1478,11 +1474,10 @@
(const struct url_data *) u))
return false;
} else {
- if (p->cookies && !cookie_callback(
- p->cookies->domain,
- (const struct cookie_data *)
- p->cookies))
- return false;
+ c = (const struct cookie_data *)p->cookies;
+ for (; c != NULL; c = c->next)
+ if (!cookie_callback(c))
+ return false;
}
/* Now, find next node to process. */
@@ -2529,8 +2524,7 @@
version = c->version;
c->last_used = now;
- cookies_update(c->domain,
- (struct cookie_data *)c);
+ cookies_update((struct cookie_data *)c);
}
}
}
@@ -2565,8 +2559,7 @@
version = c->version;
c->last_used = now;
- cookies_update(c->domain,
- (struct cookie_data *)c);
+ cookies_update((struct cookie_data *)c);
}
}
@@ -2606,7 +2599,7 @@
version = c->version;
c->last_used = now;
- cookies_update(c->domain, (struct cookie_data *)c);
+ cookies_update((struct cookie_data *)c);
}
}
@@ -2638,7 +2631,7 @@
version = c->version;
c->last_used = now;
- cookies_update(c->domain, (struct cookie_data *)c);
+ cookies_update((struct cookie_data *)c);
}
}
@@ -2928,7 +2921,7 @@
/* Now insert into database */
if (!urldb_insert_cookie(c, scheme, urlt))
goto error;
- cookies_update(c->domain, (struct cookie_data *)c);
+ cookies_update((struct cookie_data *)c);
} while (cur < end);
free(host);
@@ -3378,6 +3371,8 @@
d->prev->next = d->next;
else
p->cookies = d->next;
+
+ cookies_delete((struct cookie_data *)d);
urldb_free_cookie(d);
urldb_free_cookie(c);
} else {
@@ -3392,7 +3387,11 @@
c->prev->next = c;
else
p->cookies = c;
+
+ cookies_delete((struct cookie_data *)d);
urldb_free_cookie(d);
+
+ cookies_update((struct cookie_data *)c);
// LOG(("%p: %s=%s", c, c->name, c->value));
}
} else {
@@ -3771,9 +3770,7 @@
else
p->cookies_end = c->prev;
- if (p->cookies == NULL)
- cookies_update(domain, NULL);
-
+ cookies_delete((struct cookie_data *)c);
urldb_free_cookie(c);
return;
Index: content/urldb.h
===================================================================
--- content/urldb.h (revision 10834)
+++ content/urldb.h (working copy)
@@ -108,8 +108,7 @@
/* Iteration */
void urldb_iterate_entries(bool (*callback)(const char *url,
const struct url_data *data));
-void urldb_iterate_cookies(bool (*callback)(const char *domain,
- const struct cookie_data *cookie));
+void urldb_iterate_cookies(bool (*callback)(const struct cookie_data *cookie));
/* Debug */
void urldb_dump(void);
Conflicted files
Removed files
13 years
Review: treeview-redux [4/7] -- BeOS frontend changes
by John-Mark Bell
Added files
Changed files
beos_bitmap.cpp | 10 +++
beos_gui.cpp | 7 --
beos_scaffolding.cpp | 1
beos_treeview.cpp | 140 ++++++++++++++++-----------------------------------
4 files changed, 56 insertions(+), 102 deletions(-)
Index: beos/beos_bitmap.cpp
===================================================================
--- beos/beos_bitmap.cpp (revision 10834)
+++ beos/beos_bitmap.cpp (working copy)
@@ -312,6 +312,16 @@
struct bitmap *bitmap = (struct bitmap *)vbitmap;
}
+int bitmap_get_width(void *vbitmap){
+ struct bitmap *bitmap = (struct bitmap *)vbitmap;
+ return bitmap->primary->Bounds().Width() + 1;
+}
+
+int bitmap_get_height(void *vbitmap){
+ struct bitmap *bitmap = (struct bitmap *)vbitmap;
+ return bitmap->primary->Bounds().Height() + 1;
+}
+
static BBitmap *
nsbeos_bitmap_generate_pretile(BBitmap *primary, int repeat_x, int repeat_y)
{
Index: beos/beos_gui.cpp
===================================================================
--- beos/beos_gui.cpp (revision 10834)
+++ beos/beos_gui.cpp (working copy)
@@ -74,7 +74,6 @@
#include "beos/beos_window.h"
#include "beos/options.h"
#include "beos/beos_throbber.h"
-#include "beos/beos_history.h"
#include "beos/beos_filetype.h"
//#include "beos/beos_download.h"
#include "beos/beos_schedule.h"
@@ -641,7 +640,6 @@
urldb_load(option_url_file);
urldb_load_cookies(option_cookie_file);
- nsbeos_history_init();
//nsbeos_download_initialise();
if (!replicated)
@@ -1059,11 +1057,6 @@
exit(EXIT_FAILURE);
}
-
-void hotlist_visited(hlcache_handle *content)
-{
-}
-
void gui_cert_verify(const char *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw),
void *cbpw)
Index: beos/beos_treeview.cpp
===================================================================
--- beos/beos_treeview.cpp (revision 10834)
+++ beos/beos_treeview.cpp (working copy)
@@ -26,107 +26,59 @@
extern "C" {
#include "utils/config.h"
#include "desktop/tree.h"
+#include "desktop/tree_url_node.h"
}
+const char tree_directory_icon_name[] = "directory.png";
+const char tree_content_icon_name[] = "content.png";
-/**
- * Sets the origin variables to the correct values for a specified tree
- *
- * \param tree the tree to set the origin for
- */
-void tree_initialise_redraw(struct tree *tree) {
-}
-/**
- * Informs the current window manager that an area requires updating.
- *
- * \param tree the tree that is requesting a redraw
- * \param x the x co-ordinate of the redraw area
- * \param y the y co-ordinate of the redraw area
- * \param width the width of the redraw area
- * \param height the height of the redraw area
- */
-void tree_redraw_area(struct tree *tree, int x, int y, int width, int height) {
-}
-
/**
- * Draws a line.
+ * Translates a content_type to the name of a respective icon
*
- * \param x the x co-ordinate
- * \param x the y co-ordinate
- * \param x the width of the line
- * \param x the height of the line
+ * \param content_type content type
+ * \param buffer buffer for the icon name
*/
-void tree_draw_line(int x, int y, int width, int height) {
+void tree_icon_name_from_content_type(char *buffer, content_type type)
+{
+ // TODO: design/acquire icons
+ switch (type) {
+ case CONTENT_HTML:
+ case CONTENT_TEXTPLAIN:
+ case CONTENT_CSS:
+#if defined(WITH_MNG) || defined(WITH_PNG)
+ case CONTENT_PNG:
+#endif
+#ifdef WITH_MNG
+ case CONTENT_JNG:
+ case CONTENT_MNG:
+#endif
+#ifdef WITH_JPEG
+ case CONTENT_JPEG:
+#endif
+#ifdef WITH_GIF
+ case CONTENT_GIF:
+#endif
+#ifdef WITH_BMP
+ case CONTENT_BMP:
+ case CONTENT_ICO:
+#endif
+#ifdef WITH_SPRITE
+ case CONTENT_SPRITE:
+#endif
+#ifdef WITH_DRAW
+ case CONTENT_DRAW:
+#endif
+#ifdef WITH_ARTWORKS
+ case CONTENT_ARTWORKS:
+#endif
+#ifdef WITH_NS_SVG
+ case CONTENT_SVG:
+#endif
+ default:
+ sprintf(buffer, tree_content_icon_name);
+ break;
+ }
}
-
-
-/**
- * Draws an element, including any expansion icons
- *
- * \param tree the tree to draw an element for
- * \param element the element to draw
- */
-void tree_draw_node_element(struct tree *tree, struct node_element *element) {
-}
-
-
-/**
- * Draws an elements expansion icon
- *
- * \param tree the tree to draw the expansion for
- * \param element the element to draw the expansion for
- */
-void tree_draw_node_expansion(struct tree *tree, struct node *node) {
-}
-
-
-/**
- * Recalculates the dimensions of a node element.
- *
- * \param element the element to recalculate
- */
-void tree_recalculate_node_element(struct node_element *element) {
-}
-
-/**
- * Sets a node element as having a specific sprite.
- *
- * \param node the node to update
- * \param sprite the sprite to use
- * \param selected the expanded sprite name to use
- */
-void tree_set_node_sprite(struct node *node, const char *sprite,
- const char *expanded) {
-
-}
-
-/**
- * Sets a node element as having a folder sprite
- *
- * \param node the node to update
- */
-void tree_set_node_sprite_folder(struct node *node) {
-
-}
-
-/**
- * Updates the node details for a URL node.
- * The internal node dimensions are not updated.
- *
- * \param node the node to update
- */
-void tree_update_URL_node(struct node *node, const char *url,
- const struct url_data *data) {
-}
-
-
-/**
- * Updates the tree owner following a tree resize
- *
- * \param tree the tree to update the owner of
- */
-void tree_resized(struct tree *tree) {
-}
Index: beos/beos_scaffolding.cpp
===================================================================
--- beos/beos_scaffolding.cpp (revision 10834)
+++ beos/beos_scaffolding.cpp (working copy)
@@ -63,7 +63,6 @@
#include "beos/beos_options.h"
//#include "beos/beos_completion.h"
#include "beos/beos_throbber.h"
-//#include "beos/beos_history.h"
#include "beos/beos_window.h"
//#include "beos/beos_schedule.h"
//#include "beos/beos_download.h"
Conflicted files
Removed files
beos/beos_history.h
beos/beos_history.cpp
13 years
[RFC][PATCH] CSS2 system colors
by François Revol
Hi,
I'm way too busy to work on the BeOS port those days, but I had a try at supporting the system CSS colors some time ago, and I thought I'd send the patch anyway.
I know those are deprecated in CSS3 but well...
It's only implemented for BeOS, though it should be easy to support other platforms.
I'm not sure how it should handle printing though.
Anyway, just for the reference.
Comments ?
François.
13 years
svgtiny stoke-width / alpha support patches
by Peter Korsgaard
Hi,
I have been looking at svgtiny for some simple svg parsing, and it seems
very nice. While working on it, I've noticed that it didn't parse
stroke-width correctly, and the alpha channel isn't handled. See the
following mails for fixes for this.
--
Bye, Peter Korsgaard
13 years
Compiling
by Denis Pichugin
Hi!
I can't compile last version of NetSurf. (10834)
After
*make
I see:
make: *** No rule to make target `render/directory.h', needed by
`build-riscos-riscos/content_content.o'. Stop.
Help me, please.
--
Denis Pichugin
13 years