1 /*
2  * Copyright 2012 - 2013 Michael Drake <tlsa@netsurf-browser.org>
3  *
4  * This file is part of NetSurf, http://www.netsurf-browser.org/
5  *
6  * NetSurf is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * NetSurf is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /**
20  * \file
21  * Treeview handling interface.
22  */
23 
24 #ifndef _NETSURF_DESKTOP_TREEVIEW_H_
25 #define _NETSURF_DESKTOP_TREEVIEW_H_
26 
27 #include <stdbool.h>
28 #include <stdint.h>
29 #include <libwapcaplet/libwapcaplet.h>
30 
31 #include "netsurf/mouse.h"
32 
33 struct redraw_context;
34 struct core_window;
35 struct core_window_callback_table;
36 
37 typedef struct treeview treeview;
38 typedef struct treeview_node treeview_node;
39 
40 
41 /**
42  * treeview node type
43  */
44 enum treeview_node_type {
45 	TREE_NODE_NONE		= 0,		/**< No node  */
46 	TREE_NODE_ROOT		= (1 << 0),	/**< Node is treeview's root */
47 	TREE_NODE_FOLDER	= (1 << 1),	/**< Node is folder */
48 	TREE_NODE_ENTRY		= (1 << 2)	/**< Node is an entry */
49 };
50 
51 
52 /**
53  * Relationship between nodes
54  */
55 enum treeview_relationship {
56 	TREE_REL_FIRST_CHILD,
57 	TREE_REL_NEXT_SIBLING
58 };
59 
60 
61 /**
62  * Node change handling options
63  */
64 typedef enum {
65 	TREE_OPTION_NONE		= (0),		/* No flags set */
66 	TREE_OPTION_SPECIAL_DIR		= (1 << 0),	/* Special folder */
67 	TREE_OPTION_SUPPRESS_RESIZE	= (1 << 1),	/* Suppress callback */
68 	TREE_OPTION_SUPPRESS_REDRAW	= (1 << 2)	/* Suppress callback */
69 } treeview_node_options_flags;
70 
71 /**
72  * treeview control flags
73  */
74 typedef enum {
75 	TREEVIEW_NO_FLAGS	= (0),		/**< No flags set */
76 	TREEVIEW_NO_MOVES	= (1 << 0),	/**< No node drags */
77 	TREEVIEW_NO_DELETES	= (1 << 1),	/**< No node deletes */
78 	TREEVIEW_READ_ONLY	= TREEVIEW_NO_MOVES | TREEVIEW_NO_DELETES,
79 	TREEVIEW_DEL_EMPTY_DIRS	= (1 << 2),	/**< Delete dirs on empty */
80 	TREEVIEW_SEARCHABLE     = (1 << 3),	/**< Treeview has search bar */
81 } treeview_flags;
82 
83 /**
84  * treeview message types
85  */
86 enum treeview_msg {
87 	TREE_MSG_NODE_DELETE,		/**< Node to be deleted */
88 	TREE_MSG_NODE_EDIT,		/**< Node to be edited */
89 	TREE_MSG_NODE_LAUNCH		/**< Node to be launched */
90 };
91 
92 
93 /**
94  * treeview message
95  */
96 struct treeview_node_msg {
97 	enum treeview_msg msg; /**< The message type */
98 	union {
99 		struct {
100 			bool user; /**< True iff delete by user interaction */
101 		} delete;
102 		struct {
103 			lwc_string *field; /**< The field being edited */
104 			const char *text;  /**< The proposed new value */
105 		} node_edit; /* Client may call treeview_update_node_* */
106 		struct {
107 			browser_mouse_state mouse; /* Button / modifier used */
108 		} node_launch;
109 	} data; /**< The message data. */
110 };
111 
112 
113 /**
114  * treeview field flags
115  */
116 enum treeview_field_flags {
117 	TREE_FLAG_NONE          = 0,        /**< No flags set */
118 	TREE_FLAG_ALLOW_EDIT    = (1 << 0), /**< Whether allow edit field */
119 	TREE_FLAG_DEFAULT       = (1 << 1), /**< Whether field is default */
120 	TREE_FLAG_SHOW_NAME     = (1 << 2), /**< Whether field name shown */
121 	TREE_FLAG_COPY_TEXT     = (1 << 3), /**< Whether to copy to clipb */
122 	TREE_FLAG_SEARCHABLE    = (1 << 4), /**< Whether field is searchable */
123 };
124 
125 
126 /**
127  * Treeview field description
128  */
129 struct treeview_field_desc {
130 	lwc_string *field;			/**< A treeview field name */
131 	enum treeview_field_flags flags;	/**< Flags for field */
132 };
133 
134 
135 /**
136  * Treeview field data
137  */
138 struct treeview_field_data {
139 	lwc_string *field;		/**< Field name */
140 	const char *value;		/**< Field value */
141 	size_t value_len;		/**< Field value length (bytes) */
142 };
143 
144 
145 /**
146  * Client callbacks for events concerning nodes
147  */
148 struct treeview_callback_table {
149 	nserror (*folder)(struct treeview_node_msg msg, void *data);
150 	nserror (*entry)(struct treeview_node_msg msg, void *data);
151 };
152 
153 
154 /**
155  * Prepare treeview module for treeview usage
156  *
157  * \return NSERROR_OK on success, appropriate error otherwise
158  */
159 nserror treeview_init(void);
160 
161 
162 /**
163  * Finalise the treeview module (all treeviews must have been destroyed first)
164  *
165  * \return NSERROR_OK on success, appropriate error otherwise
166  */
167 nserror treeview_fini(void);
168 
169 
170 /**
171  * Create a treeview
172  *
173  * The fields array order is as follows (N = n_fields):
174  *
175  *    fields[0]			Main field for entries (shown when not expanded)
176  *    fields[1]...fields[N-2]	Additional fields for entries
177  *    fields[N-1]		Field for folder nodes
178  *
179  * So fields[0] and fields[N-1] have TREE_FLAG_DEFAULT set.
180  *
181  * \param tree		Returns created treeview object
182  * \param callbacks	Treeview client node event callbacks
183  * \param n_fields	Number of treeview fields (see description)
184  * \param fields	Array of treeview fields
185  * \param cw_t		Callback table for core_window containing the treeview
186  * \param cw		The core_window in which the treeview is shown
187  * \param flags		Treeview behaviour flags
188  * \return NSERROR_OK on success, appropriate error otherwise
189  */
190 nserror treeview_create(treeview **tree,
191 			const struct treeview_callback_table *callbacks,
192 			int n_fields, struct treeview_field_desc fields[],
193 			const struct core_window_callback_table *cw_t,
194 			struct core_window *cw, treeview_flags flags);
195 
196 
197 /**
198  * Attach a treeview to a corewindow.
199  *
200  * Treeview must be detached.
201  *
202  * \param tree		Treeview object
203  * \param cw_t		Callback table for core_window containing the treeview
204  * \param cw		The core_window in which the treeview is shown
205  * \return NSERROR_OK on success, appropriate error otherwise
206  */
207 nserror treeview_cw_attach(treeview *tree,
208 			   const struct core_window_callback_table *cw_t,
209 			   struct core_window *cw);
210 
211 
212 /**
213  * Detach a treeview from a corewindow
214  *
215  * \param tree Treeview object
216  * \return NSERROR_OK on success, appropriate error otherwise
217  */
218 nserror treeview_cw_detach(treeview *tree);
219 
220 
221 /**
222  * Destroy a treeview object
223  *
224  * Will emit folder and entry deletion msg callbacks for all nodes in treeview.
225  *
226  * \param tree Treeview object to destroy
227  * \return NSERROR_OK on success, appropriate error otherwise
228  */
229 nserror treeview_destroy(treeview *tree);
230 
231 
232 /**
233  * Find a relation for node creation.
234  *
235  * If at_y is set, we find a relation that will put the created node at that
236  * position.
237  *
238  * If at_y is unset, we find a relation that would put the node below the first
239  * selected node, or at the end of the treeview if no nodes selected.
240  *
241  * \param tree		Treeview object in which to create folder
242  * \param relation	Existing node to insert as relation of, or NULL
243  * \param rel		Folder's relationship to relation
244  * \param at_y		Iff true, insert at y-offset
245  * \param y		Y-offset in px from top of hotlist.  Ignored if (!at_y).
246  * \return NSERROR_OK on success, appropriate error otherwise
247  */
248 nserror treeview_get_relation(treeview *tree, treeview_node **relation,
249 			      enum treeview_relationship *rel,
250 			      bool at_y, int y);
251 
252 
253 /**
254  * Create a folder node in given treeview
255  *
256  * \param tree		Treeview object in which to create folder
257  * \param folder	Returns created folder node
258  * \param relation	Existing node to insert as relation of, or NULL
259  * \param rel		Folder's relationship to relation
260  * \param field		Field data
261  * \param data		Client data for node event callbacks
262  * \param flags		Treeview node options flags
263  * \return NSERROR_OK on success, appropriate error otherwise
264  *
265  * Field name must match name past in treeview_create fields[N-1].
266  *
267  * If relation is NULL, will insert as child of root node.
268  */
269 nserror treeview_create_node_folder(treeview *tree,
270 				    treeview_node **folder,
271 				    treeview_node *relation,
272 				    enum treeview_relationship rel,
273 				    const struct treeview_field_data *field,
274 				    void *data,
275 				    treeview_node_options_flags flags);
276 
277 
278 /**
279  * Create an entry node in given treeview
280  *
281  * \param tree		Treeview object in which to create entry
282  * \param entry		Returns created entry node
283  * \param relation	Existing node to insert as relation of, or NULL
284  * \param rel		Folder's relationship to relation
285  * \param fields	Array of field data
286  * \param data		Client data for node event callbacks
287  * \param flags		Treeview node options flags
288  * \return NSERROR_OK on success, appropriate error otherwise
289  *
290  * Fields array names must match names past in treeview_create fields[0...N-2].
291  *
292  * If relation is NULL, will insert as child of root node.
293  */
294 nserror treeview_create_node_entry(treeview *tree,
295 				   treeview_node **entry,
296 				   treeview_node *relation,
297 				   enum treeview_relationship rel,
298 				   const struct treeview_field_data fields[],
299 				   void *data,
300 				   treeview_node_options_flags flags);
301 
302 
303 /**
304  * Update an folder node in given treeview
305  *
306  * \param tree	 Treeview object in which to create entry
307  * \param folder Folder node to update
308  * \param field	 New field data
309  * \param data	 Client data for node event callbacks
310  * \return NSERROR_OK on success, appropriate error otherwise
311  *
312  * Field name must match name past in treeview_create fields[N-1].
313  */
314 nserror treeview_update_node_folder(treeview *tree,
315 				    treeview_node *folder,
316 				    const struct treeview_field_data *field,
317 				    void *data);
318 
319 
320 /**
321  * Update an entry node in given treeview
322  *
323  * \param tree		Treeview object in which to create entry
324  * \param entry		Entry node to update
325  * \param fields	Array of new field data
326  * \param data		Client data for node event callbacks
327  * \return NSERROR_OK on success, appropriate error otherwise
328  *
329  * Fields array names must match names past in treeview_create fields[0...N-2].
330  */
331 nserror treeview_update_node_entry(treeview *tree,
332 				   treeview_node *entry,
333 				   const struct treeview_field_data fields[],
334 				   void *data);
335 
336 
337 /**
338  * Client callback for treeview_walk
339  *
340  * \param ctx		Client context
341  * \param node_data	Client data for the current treeview node
342  * \param type		The node type
343  * \param abort		Set to true to abort treeview walk prematurely
344  * \return NSERROR_OK on success, or appropriate error otherwise
345  */
346 typedef nserror (*treeview_walk_cb)(void *ctx, void *node_data,
347 				    enum treeview_node_type type, bool *abort);
348 
349 
350 /**
351  * Walk (depth first) a treeview subtree, calling a callback at each node of
352  * required type.
353  *
354  * Example usage: To export a treeview as XML, XML elements can be opened in
355  * enter_cb, and closed in leave_cb.
356  *
357  * Note, if deleting returned node in enter_cb, the walk must be terminated by
358  * setting abort to true.
359  *
360  * \param tree		Treeview object to walk
361  * \param root		Root node to walk tree from (or NULL for tree root)
362  * \param enter_cb	Function to call on entering nodes, or NULL
363  * \param leave_cb	Function to call on leaving nodes, or NULL
364  * \param ctx		Client context, passed back to callback function
365  * \param type		The node type(s) of interest
366  * \return NSERROR_OK on success, or appropriate error otherwise
367  */
368 nserror treeview_walk(treeview *tree, treeview_node *root,
369 		      treeview_walk_cb enter_cb, treeview_walk_cb leave_cb,
370 		      void *ctx, enum treeview_node_type type);
371 
372 
373 /**
374  * Delete a treeview node
375  *
376  * \param tree		Treeview object to delete node from
377  * \param n		Node to delete
378  * \param flags		Treeview node options flags
379  * \return NSERROR_OK on success, appropriate error otherwise
380  *
381  * Will emit folder or entry deletion msg callback.
382  */
383 nserror treeview_delete_node(treeview *tree, treeview_node *n,
384 			     treeview_node_options_flags flags);
385 
386 
387 /**
388  * Expand a treeview node
389  *
390  * \param tree		Treeview object to expand node in
391  * \param node		Node to expand
392  * \return NSERROR_OK on success, appropriate error otherwise
393  */
394 nserror treeview_node_expand(treeview *tree, treeview_node *node);
395 
396 
397 /**
398  * Contract a treeview node
399  *
400  * \param tree		Treeview object to contract node in
401  * \param node		Node to contract
402  * \return NSERROR_OK on success, appropriate error otherwise
403  */
404 nserror treeview_node_contract(treeview *tree, treeview_node *node);
405 
406 
407 /**
408  * Expand a treeview's nodes
409  *
410  * \param tree		Treeview object to expand nodes in
411  * \param only_folders	Iff true, only folders are expanded.
412  * \return NSERROR_OK on success, appropriate error otherwise
413  */
414 nserror treeview_expand(treeview *tree, bool only_folders);
415 
416 
417 /**
418  * Contract a treeview's nodes
419  *
420  * \param tree		Treeview object to contract nodes in
421  * \param all		Iff false, only entries are contracted.
422  * \return NSERROR_OK on success, appropriate error otherwise
423  */
424 nserror treeview_contract(treeview *tree, bool all);
425 
426 
427 /**
428  * Redraw a treeview object
429  *
430  * \param tree		Treeview object to render
431  * \param x		X coordinate to render treeview at
432  * \param y		Y coordinate to render treeview at
433  * \param clip		Current clip rectangle (wrt tree origin)
434  * \param ctx		Current redraw context
435  */
436 void treeview_redraw(treeview *tree, int x, int y, struct rect *clip,
437 		     const struct redraw_context *ctx);
438 
439 
440 /**
441  * Key press handling for treeviews.
442  *
443  * \param tree		The treeview which got the keypress
444  * \param key		The ucs4 character codepoint
445  * \return true if the keypress is dealt with, false otherwise.
446  */
447 bool treeview_keypress(treeview *tree, uint32_t key);
448 
449 
450 /**
451  * Handles all kinds of mouse action
452  *
453  * \param tree		Treeview object
454  * \param mouse		The current mouse state
455  * \param x		X coordinate
456  * \param y		Y coordinate
457  */
458 void treeview_mouse_action(treeview *tree,
459 			   browser_mouse_state mouse, int x, int y);
460 
461 
462 /**
463  * Determine whether treeview has a selection
464  *
465  * \param tree Treeview object to delete node from
466  * \return true iff treeview has a selection
467  */
468 bool treeview_has_selection(treeview *tree);
469 
470 
471 /**
472  * Get the first selected node
473  *
474  * \param tree		Treeview object to get selected node in
475  * \param node_data	Client data for the selected treeview node, or NULL
476  * \return node type of first selected node.
477  */
478 enum treeview_node_type treeview_get_selection(treeview *tree,
479 					       void **node_data);
480 
481 
482 /**
483  * Edit the first selected node
484  *
485  * \param tree Treeview object to edit selected node in
486  */
487 void treeview_edit_selection(treeview *tree);
488 
489 
490 /**
491  * Find current height of a treeview
492  *
493  * \param tree Treeview object to find height of
494  * \return height of treeview in px
495  */
496 int treeview_get_height(treeview *tree);
497 
498 
499 /**
500  * Set the search string for a treeview with \ref TREEVIEW_SEARCHABLE
501  *
502  * \param tree  Tree to set the search string for.
503  * \return NSERROR_OK on success, appropriate error otherwise
504  */
505 nserror treeview_set_search_string(
506 		treeview *tree,
507 		const char *string);
508 
509 #endif
510