summaryrefslogtreecommitdiff
path: root/desktop
diff options
context:
space:
mode:
Diffstat (limited to 'desktop')
-rw-r--r--desktop/global_history.c73
-rw-r--r--desktop/treeview.c253
-rw-r--r--desktop/treeview.h22
3 files changed, 275 insertions, 73 deletions
diff --git a/desktop/global_history.c b/desktop/global_history.c
index 17fabb069..36f288039 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -60,6 +60,7 @@ struct global_history_ctx {
struct global_history_ctx gh_ctx;
struct global_history_entry {
+ int slot;
nsurl *url;
time_t t;
struct treeview_node *entry;
@@ -77,8 +78,7 @@ struct global_history_entry *gh_list[N_DAYS];
* \param url The URL to find
* \return Pointer to node, or NULL if not found
*/
-static struct global_history_entry *global_history_find(nsurl *url,
- int *slot)
+static struct global_history_entry *global_history_find(nsurl *url)
{
int i;
struct global_history_entry *e;
@@ -89,7 +89,6 @@ static struct global_history_entry *global_history_find(nsurl *url,
while (e != NULL) {
if (nsurl_compare(e->url, url,
NSURL_COMPLETE) == true) {
- *slot = i;
return e;
}
e = e->next;
@@ -136,20 +135,20 @@ static nserror global_history_create_treeview_field_data(
const struct url_data *data)
{
e->data[0].field = gh_ctx.fields[0].field;
+ e->data[0].value = strdup(data->title);
e->data[0].value_len = strlen(data->title);
- e->data[0].value = data->title;
e->data[1].field = gh_ctx.fields[1].field;
e->data[1].value = nsurl_access(e->url);
- e->data[1].value_len = strlen(nsurl_access(e->url));
+ e->data[1].value_len = nsurl_length(e->url);
e->data[2].field = gh_ctx.fields[2].field;
- e->data[2].value = "node last visit data";
- e->data[2].value_len = SLEN("node last visit data");
+ e->data[2].value = "Date time";
+ e->data[2].value_len = SLEN("Last visited");
e->data[3].field = gh_ctx.fields[3].field;
- e->data[3].value = "node visi count data";
- e->data[3].value_len = SLEN("node visi count data");
+ e->data[3].value = "Count";
+ e->data[3].value_len = SLEN("Count");
return NSERROR_OK;
}
@@ -197,6 +196,7 @@ static nserror global_history_add_entry_internal(nsurl *url, int slot,
return false;
}
+ e->slot = slot;
e->url = nsurl_ref(url);
e->t = data->last_visit;
e->entry = NULL;
@@ -215,6 +215,7 @@ static nserror global_history_add_entry_internal(nsurl *url, int slot,
} else if (gh_list[slot]->t < e->t) {
/* Insert at list head */
e->next = gh_list[slot];
+ gh_list[slot]->prev = e;
gh_list[slot] = e;
} else {
struct global_history_entry *prev = gh_list[slot];
@@ -247,12 +248,12 @@ static nserror global_history_add_entry_internal(nsurl *url, int slot,
}
static void global_history_delete_entry_internal(
- struct global_history_entry *e,
- int slot)
+ struct global_history_entry *e)
{
- if (gh_list[slot] == e) {
+ /* Unlink */
+ if (gh_list[e->slot] == e) {
/* e is first entry */
- gh_list[slot] = e->next;
+ gh_list[e->slot] = e->next;
if (e->next != NULL)
e->next->prev = NULL;
@@ -267,8 +268,9 @@ static void global_history_delete_entry_internal(
e->next->prev = e->prev;
}
- /* TODO: Delete treeview node */
-
+ /* Destroy */
+ free((void *)e->data[0].value); /* Eww */
+ nsurl_unref(e->url);
free(e);
}
@@ -283,7 +285,6 @@ static bool global_history_add_entry(nsurl *url,
const struct url_data *data)
{
int slot;
- int existing_slot;
struct global_history_entry *e;
time_t visit_date;
time_t earliest_date = gh_ctx.today - (N_DAYS - 1) * N_SEC_PER_DAY;
@@ -307,10 +308,10 @@ static bool global_history_add_entry(nsurl *url,
/* The treeview for global history already exists */
/* See if there's already an entry for this URL */
- e = global_history_find(url, &existing_slot);
+ e = global_history_find(url);
if (e != NULL) {
/* Existing entry. Delete it. */
- global_history_delete_entry_internal(e, existing_slot);
+ treeview_delete_node(gh_ctx.tree, e->entry);
return true;
}
}
@@ -374,7 +375,7 @@ static nserror global_history_initialise_entry_fields(void)
return NSERROR_OK;
error:
- for (i = 0; i < N_FIELDS - 1; i++)
+ for (i = 0; i < N_FIELDS; i++)
if (gh_ctx.fields[i].field != NULL)
lwc_string_unref(gh_ctx.fields[i].field);
@@ -422,8 +423,8 @@ static nserror global_history_initialise_time(void)
*
* \return true on success, false on memory exhaustion
*/
-static nserror global_history_init_dir(
- enum global_history_folders f, const char *label, int age)
+static nserror global_history_init_dir(enum global_history_folders f,
+ const char *label, int age)
{
nserror err;
time_t t = gh_ctx.today;
@@ -439,7 +440,7 @@ static nserror global_history_init_dir(
rel = TREE_REL_SIBLING_NEXT;
}
- gh_ctx.folders[f].data.field = gh_ctx.fields[4].field;
+ gh_ctx.folders[f].data.field = gh_ctx.fields[N_FIELDS - 1].field;
gh_ctx.folders[f].data.value = label;
gh_ctx.folders[f].data.value_len = strlen(label);
err = treeview_create_node_folder(gh_ctx.tree,
@@ -530,6 +531,16 @@ static nserror global_history_tree_node_folder_cb(
static nserror global_history_tree_node_entry_cb(
struct treeview_node_msg msg, void *data)
{
+ struct global_history_entry *e = (struct global_history_entry *)data;
+
+ switch (msg.msg) {
+ case TREE_MSG_NODE_DELETE:
+ global_history_delete_entry_internal(e);
+ break;
+
+ case TREE_MSG_FIELD_EDIT:
+ break;
+ }
return NSERROR_OK;
}
struct treeview_callback_table tree_cb_t = {
@@ -583,6 +594,8 @@ nserror global_history_init(struct core_window_callback_table *cw_t,
return err;
}
+ LOG(("Building global history treeview"));
+
/* Add the history to the treeview */
err = global_history_init_entries();
if (err != NSERROR_OK) {
@@ -614,26 +627,18 @@ nserror global_history_fini(struct core_window_callback_table *cw_t,
int i;
nserror err;
+ LOG(("Finalising global history"));
+
/* Destroy the global history treeview */
err = treeview_destroy(gh_ctx.tree);
- /* Free global history entry data */
- for (i = 0; i < N_DAYS; i++) {
- struct global_history_entry *t;
- struct global_history_entry *e = gh_list[i];
- while (e != NULL) {
- t = e;
- e = e->next;
- nsurl_unref(t->url);
- free(t);
- }
- }
-
/* Free global history treeview entry fields */
for (i = 0; i < N_FIELDS; i++)
if (gh_ctx.fields[i].field != NULL)
lwc_string_unref(gh_ctx.fields[i].field);
+ LOG(("Finalised global history"));
+
return NSERROR_OK;
}
diff --git a/desktop/treeview.c b/desktop/treeview.c
index de731f298..9d3dce54a 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -31,7 +31,7 @@
#define FIELD_FIRST_ENTRY 1
struct treeview_globals {
- int line_height;
+ uint32_t line_height;
int furniture_width;
int step_width;
int window_padding;
@@ -81,7 +81,7 @@ struct treeview_node {
};
struct treeview_node_entry {
- struct treeview_node *base;
+ struct treeview_node base;
struct treeview_field fields[];
};
@@ -328,18 +328,18 @@ nserror treeview_update_node_entry(struct treeview *tree,
fields[i].field, &match) == lwc_error_ok &&
match == true);
- e->fields[i].value.data = fields[i].value;
- e->fields[i].value.len = fields[i].value_len;
+ e->fields[i - 1].value.data = fields[i].value;
+ e->fields[i - 1].value.len = fields[i].value_len;
if (entry->flags & TREE_NODE_EXPANDED) {
/* Text will be seen, get its width */
nsfont.font_width(&plot_style_odd.text,
- e->fields[i].value.data,
- e->fields[i].value.len,
- &(e->fields[i].value.width));
+ e->fields[i - 1].value.data,
+ e->fields[i - 1].value.len,
+ &(e->fields[i - 1].value.width));
} else {
/* Invalidate the width, since it's not needed yet */
- entry->text.value.width = 0;
+ e->fields[i - 1].value.width = 0;
}
}
@@ -369,11 +369,12 @@ nserror treeview_create_node_entry(struct treeview *tree,
}
e = malloc(sizeof(struct treeview_node_entry) +
- tree->n_fields * sizeof(struct treeview_field));
+ (tree->n_fields - 1) * sizeof(struct treeview_field));
if (e == NULL) {
return NSERROR_NOMEM;
}
+
n = (struct treeview_node *) e;
n->flags = TREE_NODE_NONE;
@@ -403,9 +404,9 @@ nserror treeview_create_node_entry(struct treeview *tree,
fields[i].field, &match) == lwc_error_ok &&
match == true);
- e->fields[i].value.data = fields[i].value;
- e->fields[i].value.len = fields[i].value_len;
- e->fields[i].value.width = 0;
+ e->fields[i - 1].value.data = fields[i].value;
+ e->fields[i - 1].value.len = fields[i].value_len;
+ e->fields[i - 1].value.width = 0;
}
treeview_insert_node(n, relation, rel);
@@ -416,11 +417,15 @@ nserror treeview_create_node_entry(struct treeview *tree,
}
-nserror treeview_delete_node(struct treeview_node *n)
+nserror treeview_delete_node(struct treeview *tree, struct treeview_node *n)
{
+ struct treeview_node_msg msg;
+ msg.msg = TREE_MSG_NODE_DELETE;
+ msg.data.node_delete.node = n;
+
/* Destroy children first */
while (n->children != NULL) {
- treeview_delete_node(n->children);
+ treeview_delete_node(tree, n->children);
}
/* Unlink node from tree */
@@ -441,8 +446,10 @@ nserror treeview_delete_node(struct treeview_node *n)
/* Handle any special treatment */
switch (n->type) {
case TREE_NODE_ENTRY:
+ tree->callbacks->entry(msg, n->client_data);
break;
case TREE_NODE_FOLDER:
+ tree->callbacks->folder(msg, n->client_data);
break;
case TREE_NODE_ROOT:
break;
@@ -528,7 +535,7 @@ nserror treeview_destroy(struct treeview *tree)
assert(tree != NULL);
/* Destroy nodes */
- treeview_delete_node(tree->root);
+ treeview_delete_node(tree, tree->root);
/* Destroy feilds */
for (f = 0; f <= tree->n_fields; f++) {
@@ -573,7 +580,7 @@ static bool treeview_walk_internal(struct treeview_node *root, bool full,
/* no children */
next = node->sibling_next;
- if (next != NULL) {
+ if (next != NULL && node != root) {
/* on to next sibling */
node = next;
} else {
@@ -655,7 +662,7 @@ nserror treeview_node_expand(struct treeview *tree,
e = (struct treeview_node_entry *)node;
- for (i = 1; i < tree->n_fields; i++) {
+ for (i = 0; i < tree->n_fields - 1; i++) {
if (e->fields[i].value.width == 0) {
nsfont.font_width(&plot_style_odd.text,
@@ -703,7 +710,7 @@ static bool treeview_node_contract_cb(struct treeview_node *node, int inset,
return false;
}
- node->flags |= ~TREE_NODE_EXPANDED;
+ node->flags ^= TREE_NODE_EXPANDED;
height_reduction = node->height - tree_g.line_height;
assert(height_reduction >= 0);
@@ -711,7 +718,8 @@ static bool treeview_node_contract_cb(struct treeview_node *node, int inset,
do {
node->height -= height_reduction;
node = node->parent;
- } while (node->parent != NULL);
+ } while (node->parent != NULL &&
+ node->parent->flags & TREE_NODE_EXPANDED);
return false; /* Don't want to abort tree walk */
}
@@ -761,6 +769,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect *clip,
enum treeview_resource_id res;
plot_style_t *bg;
plot_font_style_t *text;
+ int height;
assert(tree != NULL);
assert(tree->root != NULL);
@@ -826,10 +835,14 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect *clip,
assert(node != root);
count++;
+ height = (node->type == TREE_NODE_ENTRY) ? node->height :
+ tree_g.line_height;
- if (render_y + tree_g.line_height < clip->y0) {
+ if (clip->y0 >= 0 &&
+ render_y + tree_g.line_height <
+ (unsigned)clip->y0) {
/* This node's line is above clip region */
- render_y += tree_g.line_height;
+ render_y += height;
continue;
}
@@ -844,7 +857,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect *clip,
/* Render background */
y0 = render_y;
- y1 = render_y + tree_g.line_height;
+ y1 = render_y + height;
new_ctx.plot->rectangle(r.x0, y0, r.x1, y1, bg);
/* Render toggle */
@@ -897,19 +910,14 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect *clip,
/* Done everything for this node */
continue;
-
- /* Reneder expanded entry background */
- y0 = render_y;
- y1 = render_y + tree_g.line_height * tree->n_fields;
- new_ctx.plot->rectangle(r.x0, y0, r.x1, y1, bg);
-
/* Render expanded entry fields */
entry = (struct treeview_node_entry *)node;
- for (i = 0; i < tree->n_fields; i++) {
- struct treeview_field *ef = &(tree->fields[i]);
- int max_width = tree->field_width;
+ for (i = 0; i < tree->n_fields - 1; i++) {
+ struct treeview_field *ef = &(tree->fields[i + 1]);
if (ef->flags & TREE_FLAG_SHOW_NAME) {
+ int max_width = tree->field_width;
+
new_ctx.plot->text(x0 + max_width -
ef->value.width -
tree_g.step_width,
@@ -956,6 +964,122 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect *clip,
knockout_plot_end();
}
+struct treeview_selection_walk_data {
+ enum {
+ TREEVIEW_WALK_HAS_SELECTION,
+ TREEVIEW_WALK_CLEAR_SELECTION,
+ TREEVIEW_WALK_SELECT_ALL
+ } purpose;
+ union {
+ bool has_selection;
+ struct {
+ bool required;
+ struct rect *rect;
+ } redraw;
+ } data;
+ int current_y;
+};
+static bool treeview_node_selection_walk_cb(struct treeview_node *node,
+ int inset, void *ctx)
+{
+ struct treeview_selection_walk_data *sw = ctx;
+ int height;
+ bool changed = false;
+
+ height = (node->type == TREE_NODE_ENTRY) ? node->height :
+ tree_g.line_height;
+ sw->current_y += height;
+
+ switch (sw->purpose) {
+ case TREEVIEW_WALK_HAS_SELECTION:
+ if (node->flags & TREE_NODE_SELECTED) {
+ sw->data.has_selection = true;
+ return true; /* Can abort tree walk */
+ }
+ break;
+
+ case TREEVIEW_WALK_CLEAR_SELECTION:
+ if (node->flags & TREE_NODE_SELECTED) {
+ node->flags ^= TREE_NODE_SELECTED;
+ changed = true;
+ }
+ break;
+
+ case TREEVIEW_WALK_SELECT_ALL:
+ if (!(node->flags & TREE_NODE_SELECTED)) {
+ node->flags ^= TREE_NODE_SELECTED;
+ changed = true;
+ }
+ break;
+ }
+
+ if (changed) {
+ if (sw->data.redraw.required == false) {
+ sw->data.redraw.required = true;
+ sw->data.redraw.rect->y0 = sw->current_y - height;
+ }
+
+ if (sw->current_y > sw->data.redraw.rect->y1) {
+ sw->data.redraw.rect->y1 = sw->current_y;
+ }
+ }
+
+ return false; /* Don't stop walk */
+}
+
+bool treeview_has_selection(struct treeview *tree)
+{
+ struct treeview_selection_walk_data sw;
+
+ sw.purpose = TREEVIEW_WALK_HAS_SELECTION;
+ sw.data.has_selection = false;
+
+ treeview_walk_internal(tree->root, false,
+ treeview_node_selection_walk_cb, &sw);
+
+ return sw.data.has_selection;
+}
+
+bool treeview_clear_selection(struct treeview *tree, struct rect *rect)
+{
+ struct treeview_selection_walk_data sw;
+
+ rect->x0 = 0;
+ rect->y0 = 0;
+ rect->x1 = INT_MAX;
+ rect->y1 = 0;
+
+ sw.purpose = TREEVIEW_WALK_CLEAR_SELECTION;
+ sw.data.redraw.required = false;
+ sw.data.redraw.rect = rect;
+ sw.current_y = 0;
+
+ treeview_walk_internal(tree->root, false,
+ treeview_node_selection_walk_cb, &sw);
+
+ return sw.data.redraw.required;
+}
+
+bool treeview_select_all(struct treeview *tree, struct rect *rect)
+{
+ struct treeview_selection_walk_data sw;
+
+ rect->x0 = 0;
+ rect->y0 = 0;
+ rect->x1 = INT_MAX;
+ rect->y1 = 0;
+
+ sw.purpose = TREEVIEW_WALK_SELECT_ALL;
+ sw.data.redraw.required = false;
+ sw.data.redraw.rect = rect;
+ sw.current_y = 0;
+
+ treeview_walk_internal(tree->root, false,
+ treeview_node_selection_walk_cb, &sw);
+
+ return sw.data.redraw.required;
+}
+
struct treeview_mouse_action {
struct treeview *tree;
browser_mouse_state mouse;
@@ -968,20 +1092,73 @@ static bool treeview_node_mouse_action_cb(struct treeview_node *node,
{
struct treeview_mouse_action *ma = ctx;
struct rect r;
+ bool redraw = false;
+ int height;
+ enum {
+ TV_NODE_ACTION_NONE = 0,
+ TV_NODE_ACTION_SELECTION = (1 << 0)
+ } action = TV_NODE_ACTION_NONE;
+ nserror err;
+
+ r.x0 = 0;
+ r.x1 = INT_MAX;
+
+ height = (node->type == TREE_NODE_ENTRY) ? node->height :
+ tree_g.line_height;
/* Skip line if we've not reached mouse y */
- if (ma->y > ma->current_y + tree_g.line_height) {
- ma->current_y += tree_g.line_height;
+ if (ma->y > ma->current_y + height) {
+ ma->current_y += height;
return false; /* Don't want to abort tree walk */
}
- if (ma->mouse & BROWSER_MOUSE_CLICK_1) {
- node->flags ^= TREE_NODE_SELECTED;
+ if ((ma->mouse & BROWSER_MOUSE_DOUBLE_CLICK) &&
+ (ma->mouse & BROWSER_MOUSE_CLICK_1)) {
+ /* Clear any existing selection */
+ redraw |= treeview_clear_selection(ma->tree, &r);
- r.x0 = 0;
+ /* TODO: launch callback for entry */
+ /* TODO: for now expand/collapse both directories and entries */
+ if (node->flags & TREE_NODE_EXPANDED) {
+ err = treeview_node_contract(ma->tree, node);
+ } else {
+ err = treeview_node_expand(ma->tree, node);
+ }
+ redraw = true;
r.y0 = ma->current_y;
- r.x1 = INT_MAX;
- r.y1 = ma->current_y + tree_g.line_height;
+ r.y1 = INT_MAX;
+
+ } else if (ma->mouse & BROWSER_MOUSE_PRESS_1 &&
+ !(node->flags & TREE_NODE_SELECTED)) {
+ /* Clear any existing selection */
+ redraw |= treeview_clear_selection(ma->tree, &r);
+
+ /* Select node */
+ action |= TV_NODE_ACTION_SELECTION;
+
+ } else if (ma->mouse & BROWSER_MOUSE_PRESS_2) {
+ /* Toggle selection of node */
+ action |= TV_NODE_ACTION_SELECTION;
+ }
+
+ if (action & TV_NODE_ACTION_SELECTION) {
+ /* Handle change in selection */
+ node->flags ^= TREE_NODE_SELECTED;
+
+ /* Redraw */
+ if (!redraw) {
+ r.y0 = ma->current_y;
+ r.y1 = ma->current_y + height;
+ redraw = true;
+ } else {
+ if (r.y0 > ma->current_y)
+ r.y0 = ma->current_y;
+ if (r.y1 < ma->current_y + height)
+ r.y1 = ma->current_y + height;
+ }
+ }
+
+ if (redraw) {
ma->tree->cw_t->redraw_request(ma->tree->cw_h, r);
}
diff --git a/desktop/treeview.h b/desktop/treeview.h
index 2f4e0c80d..21ecfe808 100644
--- a/desktop/treeview.h
+++ b/desktop/treeview.h
@@ -108,7 +108,7 @@ nserror treeview_update_node_entry(struct treeview *tree,
const struct treeview_field_data fields[],
void *data);
-nserror treeview_delete_node(struct treeview_node *n);
+nserror treeview_delete_node(struct treeview *tree, struct treeview_node *n);
nserror treeview_node_expand(struct treeview *tree,
struct treeview_node *node);
@@ -131,4 +131,24 @@ void treeview_mouse_action(struct treeview *tree,
struct treeview_node * treeview_get_root(struct treeview *tree);
+bool treeview_has_selection(struct treeview *tree);
+
+/**
+ * Clear any selection in a treeview
+ *
+ * \param tree treeview to clear selection in
+ * \param rect redraw rectangle (if redraw required)
+ * \return true iff redraw required
+ */
+bool treeview_clear_selection(struct treeview *tree, struct rect *rect);
+
+/**
+ * Select all in a treeview
+ *
+ * \param tree treeview to select all in
+ * \param rect redraw rectangle (if redraw required)
+ * \return true iff redraw required
+ */
+bool treeview_select_all(struct treeview *tree, struct rect *rect);
+
#endif