1 /*
2  * This file is part of gtkD.
3  *
4  * gtkD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 3
7  * of the License, or (at your option) any later version, with
8  * some exceptions, please read the COPYING file.
9  *
10  * gtkD 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 Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with gtkD; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
18  */
19 
20 // generated automatically - do not change
21 // find conversion definition on APILookup.txt
22 // implement new conversion functionalities on the wrap.utils pakage
23 
24 
25 module gtk.EntryCompletion;
26 
27 private import glib.ConstructionException;
28 private import glib.Str;
29 private import gobject.ObjectG;
30 private import gobject.Signals;
31 private import gtk.BuildableIF;
32 private import gtk.BuildableT;
33 private import gtk.CellArea;
34 private import gtk.CellLayoutIF;
35 private import gtk.CellLayoutT;
36 private import gtk.TreeIter;
37 private import gtk.TreeModel;
38 private import gtk.TreeModelIF;
39 private import gtk.Widget;
40 private import gtkc.gtk;
41 public  import gtkc.gtktypes;
42 private import std.algorithm;
43 
44 
45 /**
46  * #GtkEntryCompletion is an auxiliary object to be used in conjunction with
47  * #GtkEntry to provide the completion functionality. It implements the
48  * #GtkCellLayout interface, to allow the user to add extra cells to the
49  * #GtkTreeView with completion matches.
50  * 
51  * “Completion functionality” means that when the user modifies the text
52  * in the entry, #GtkEntryCompletion checks which rows in the model match
53  * the current content of the entry, and displays a list of matches.
54  * By default, the matching is done by comparing the entry text
55  * case-insensitively against the text column of the model (see
56  * gtk_entry_completion_set_text_column()), but this can be overridden
57  * with a custom match function (see gtk_entry_completion_set_match_func()).
58  * 
59  * When the user selects a completion, the content of the entry is
60  * updated. By default, the content of the entry is replaced by the
61  * text column of the model, but this can be overridden by connecting
62  * to the #GtkEntryCompletion::match-selected signal and updating the
63  * entry in the signal handler. Note that you should return %TRUE from
64  * the signal handler to suppress the default behaviour.
65  * 
66  * To add completion functionality to an entry, use gtk_entry_set_completion().
67  * 
68  * In addition to regular completion matches, which will be inserted into the
69  * entry when they are selected, #GtkEntryCompletion also allows to display
70  * “actions” in the popup window. Their appearance is similar to menuitems,
71  * to differentiate them clearly from completion strings. When an action is
72  * selected, the #GtkEntryCompletion::action-activated signal is emitted.
73  * 
74  * GtkEntryCompletion uses a #GtkTreeModelFilter model to represent the
75  * subset of the entire model that is currently matching. While the
76  * GtkEntryCompletion signals #GtkEntryCompletion::match-selected and
77  * #GtkEntryCompletion::cursor-on-match take the original model and an
78  * iter pointing to that model as arguments, other callbacks and signals
79  * (such as #GtkCellLayoutDataFuncs or #GtkCellArea::apply-attributes)
80  * will generally take the filter model as argument. As long as you are
81  * only calling gtk_tree_model_get(), this will make no difference to
82  * you. If for some reason, you need the original model, use
83  * gtk_tree_model_filter_get_model(). Don’t forget to use
84  * gtk_tree_model_filter_convert_iter_to_child_iter() to obtain a
85  * matching iter.
86  */
87 public class EntryCompletion : ObjectG, BuildableIF, CellLayoutIF
88 {
89 	/** the main Gtk struct */
90 	protected GtkEntryCompletion* gtkEntryCompletion;
91 
92 	/** Get the main Gtk struct */
93 	public GtkEntryCompletion* getEntryCompletionStruct(bool transferOwnership = false)
94 	{
95 		if (transferOwnership)
96 			ownedRef = false;
97 		return gtkEntryCompletion;
98 	}
99 
100 	/** the main Gtk struct as a void* */
101 	protected override void* getStruct()
102 	{
103 		return cast(void*)gtkEntryCompletion;
104 	}
105 
106 	protected override void setStruct(GObject* obj)
107 	{
108 		gtkEntryCompletion = cast(GtkEntryCompletion*)obj;
109 		super.setStruct(obj);
110 	}
111 
112 	/**
113 	 * Sets our main struct and passes it to the parent class.
114 	 */
115 	public this (GtkEntryCompletion* gtkEntryCompletion, bool ownedRef = false)
116 	{
117 		this.gtkEntryCompletion = gtkEntryCompletion;
118 		super(cast(GObject*)gtkEntryCompletion, ownedRef);
119 	}
120 
121 	// add the Buildable capabilities
122 	mixin BuildableT!(GtkEntryCompletion);
123 
124 	// add the CellLayout capabilities
125 	mixin CellLayoutT!(GtkEntryCompletion);
126 
127 
128 	/** */
129 	public static GType getType()
130 	{
131 		return gtk_entry_completion_get_type();
132 	}
133 
134 	/**
135 	 * Creates a new #GtkEntryCompletion object.
136 	 *
137 	 * Returns: A newly created #GtkEntryCompletion object
138 	 *
139 	 * Since: 2.4
140 	 *
141 	 * Throws: ConstructionException GTK+ fails to create the object.
142 	 */
143 	public this()
144 	{
145 		auto p = gtk_entry_completion_new();
146 		
147 		if(p is null)
148 		{
149 			throw new ConstructionException("null returned by new");
150 		}
151 		
152 		this(cast(GtkEntryCompletion*) p, true);
153 	}
154 
155 	/**
156 	 * Creates a new #GtkEntryCompletion object using the
157 	 * specified @area to layout cells in the underlying
158 	 * #GtkTreeViewColumn for the drop-down menu.
159 	 *
160 	 * Params:
161 	 *     area = the #GtkCellArea used to layout cells
162 	 *
163 	 * Returns: A newly created #GtkEntryCompletion object
164 	 *
165 	 * Since: 3.0
166 	 *
167 	 * Throws: ConstructionException GTK+ fails to create the object.
168 	 */
169 	public this(CellArea area)
170 	{
171 		auto p = gtk_entry_completion_new_with_area((area is null) ? null : area.getCellAreaStruct());
172 		
173 		if(p is null)
174 		{
175 			throw new ConstructionException("null returned by new_with_area");
176 		}
177 		
178 		this(cast(GtkEntryCompletion*) p, true);
179 	}
180 
181 	/**
182 	 * Requests a completion operation, or in other words a refiltering of the
183 	 * current list with completions, using the current key. The completion list
184 	 * view will be updated accordingly.
185 	 *
186 	 * Since: 2.4
187 	 */
188 	public void complete()
189 	{
190 		gtk_entry_completion_complete(gtkEntryCompletion);
191 	}
192 
193 	/**
194 	 * Computes the common prefix that is shared by all rows in @completion
195 	 * that start with @key. If no row matches @key, %NULL will be returned.
196 	 * Note that a text column must have been set for this function to work,
197 	 * see gtk_entry_completion_set_text_column() for details.
198 	 *
199 	 * Params:
200 	 *     key = The text to complete for
201 	 *
202 	 * Returns: The common prefix all rows starting with
203 	 *     @key or %NULL if no row matches @key.
204 	 *
205 	 * Since: 3.4
206 	 */
207 	public string computePrefix(string key)
208 	{
209 		auto retStr = gtk_entry_completion_compute_prefix(gtkEntryCompletion, Str.toStringz(key));
210 		
211 		scope(exit) Str.freeString(retStr);
212 		return Str.toString(retStr);
213 	}
214 
215 	/**
216 	 * Deletes the action at @index_ from @completion’s action list.
217 	 *
218 	 * Note that @index_ is a relative position and the position of an
219 	 * action may have changed since it was inserted.
220 	 *
221 	 * Params:
222 	 *     index = the index of the item to delete
223 	 *
224 	 * Since: 2.4
225 	 */
226 	public void deleteAction(int index)
227 	{
228 		gtk_entry_completion_delete_action(gtkEntryCompletion, index);
229 	}
230 
231 	/**
232 	 * Get the original text entered by the user that triggered
233 	 * the completion or %NULL if there’s no completion ongoing.
234 	 *
235 	 * Returns: the prefix for the current completion
236 	 *
237 	 * Since: 2.12
238 	 */
239 	public string getCompletionPrefix()
240 	{
241 		return Str.toString(gtk_entry_completion_get_completion_prefix(gtkEntryCompletion));
242 	}
243 
244 	/**
245 	 * Gets the entry @completion has been attached to.
246 	 *
247 	 * Returns: The entry @completion has been attached to
248 	 *
249 	 * Since: 2.4
250 	 */
251 	public Widget getEntry()
252 	{
253 		auto p = gtk_entry_completion_get_entry(gtkEntryCompletion);
254 		
255 		if(p is null)
256 		{
257 			return null;
258 		}
259 		
260 		return ObjectG.getDObject!(Widget)(cast(GtkWidget*) p);
261 	}
262 
263 	/**
264 	 * Returns whether the common prefix of the possible completions should
265 	 * be automatically inserted in the entry.
266 	 *
267 	 * Returns: %TRUE if inline completion is turned on
268 	 *
269 	 * Since: 2.6
270 	 */
271 	public bool getInlineCompletion()
272 	{
273 		return gtk_entry_completion_get_inline_completion(gtkEntryCompletion) != 0;
274 	}
275 
276 	/**
277 	 * Returns %TRUE if inline-selection mode is turned on.
278 	 *
279 	 * Returns: %TRUE if inline-selection mode is on
280 	 *
281 	 * Since: 2.12
282 	 */
283 	public bool getInlineSelection()
284 	{
285 		return gtk_entry_completion_get_inline_selection(gtkEntryCompletion) != 0;
286 	}
287 
288 	/**
289 	 * Returns the minimum key length as set for @completion.
290 	 *
291 	 * Returns: The currently used minimum key length
292 	 *
293 	 * Since: 2.4
294 	 */
295 	public int getMinimumKeyLength()
296 	{
297 		return gtk_entry_completion_get_minimum_key_length(gtkEntryCompletion);
298 	}
299 
300 	/**
301 	 * Returns the model the #GtkEntryCompletion is using as data source.
302 	 * Returns %NULL if the model is unset.
303 	 *
304 	 * Returns: A #GtkTreeModel, or %NULL if none
305 	 *     is currently being used
306 	 *
307 	 * Since: 2.4
308 	 */
309 	public TreeModelIF getModel()
310 	{
311 		auto p = gtk_entry_completion_get_model(gtkEntryCompletion);
312 		
313 		if(p is null)
314 		{
315 			return null;
316 		}
317 		
318 		return ObjectG.getDObject!(TreeModel, TreeModelIF)(cast(GtkTreeModel*) p);
319 	}
320 
321 	/**
322 	 * Returns whether the completions should be presented in a popup window.
323 	 *
324 	 * Returns: %TRUE if popup completion is turned on
325 	 *
326 	 * Since: 2.6
327 	 */
328 	public bool getPopupCompletion()
329 	{
330 		return gtk_entry_completion_get_popup_completion(gtkEntryCompletion) != 0;
331 	}
332 
333 	/**
334 	 * Returns whether the  completion popup window will be resized to the
335 	 * width of the entry.
336 	 *
337 	 * Returns: %TRUE if the popup window will be resized to the width of
338 	 *     the entry
339 	 *
340 	 * Since: 2.8
341 	 */
342 	public bool getPopupSetWidth()
343 	{
344 		return gtk_entry_completion_get_popup_set_width(gtkEntryCompletion) != 0;
345 	}
346 
347 	/**
348 	 * Returns whether the completion popup window will appear even if there is
349 	 * only a single match.
350 	 *
351 	 * Returns: %TRUE if the popup window will appear regardless of the
352 	 *     number of matches
353 	 *
354 	 * Since: 2.8
355 	 */
356 	public bool getPopupSingleMatch()
357 	{
358 		return gtk_entry_completion_get_popup_single_match(gtkEntryCompletion) != 0;
359 	}
360 
361 	/**
362 	 * Returns the column in the model of @completion to get strings from.
363 	 *
364 	 * Returns: the column containing the strings
365 	 *
366 	 * Since: 2.6
367 	 */
368 	public int getTextColumn()
369 	{
370 		return gtk_entry_completion_get_text_column(gtkEntryCompletion);
371 	}
372 
373 	/**
374 	 * Inserts an action in @completion’s action item list at position @index_
375 	 * with markup @markup.
376 	 *
377 	 * Params:
378 	 *     index = the index of the item to insert
379 	 *     markup = markup of the item to insert
380 	 *
381 	 * Since: 2.4
382 	 */
383 	public void insertActionMarkup(int index, string markup)
384 	{
385 		gtk_entry_completion_insert_action_markup(gtkEntryCompletion, index, Str.toStringz(markup));
386 	}
387 
388 	/**
389 	 * Inserts an action in @completion’s action item list at position @index_
390 	 * with text @text. If you want the action item to have markup, use
391 	 * gtk_entry_completion_insert_action_markup().
392 	 *
393 	 * Note that @index_ is a relative position in the list of actions and
394 	 * the position of an action can change when deleting a different action.
395 	 *
396 	 * Params:
397 	 *     index = the index of the item to insert
398 	 *     text = text of the item to insert
399 	 *
400 	 * Since: 2.4
401 	 */
402 	public void insertActionText(int index, string text)
403 	{
404 		gtk_entry_completion_insert_action_text(gtkEntryCompletion, index, Str.toStringz(text));
405 	}
406 
407 	/**
408 	 * Requests a prefix insertion.
409 	 *
410 	 * Since: 2.6
411 	 */
412 	public void insertPrefix()
413 	{
414 		gtk_entry_completion_insert_prefix(gtkEntryCompletion);
415 	}
416 
417 	/**
418 	 * Sets whether the common prefix of the possible completions should
419 	 * be automatically inserted in the entry.
420 	 *
421 	 * Params:
422 	 *     inlineCompletion = %TRUE to do inline completion
423 	 *
424 	 * Since: 2.6
425 	 */
426 	public void setInlineCompletion(bool inlineCompletion)
427 	{
428 		gtk_entry_completion_set_inline_completion(gtkEntryCompletion, inlineCompletion);
429 	}
430 
431 	/**
432 	 * Sets whether it is possible to cycle through the possible completions
433 	 * inside the entry.
434 	 *
435 	 * Params:
436 	 *     inlineSelection = %TRUE to do inline selection
437 	 *
438 	 * Since: 2.12
439 	 */
440 	public void setInlineSelection(bool inlineSelection)
441 	{
442 		gtk_entry_completion_set_inline_selection(gtkEntryCompletion, inlineSelection);
443 	}
444 
445 	/**
446 	 * Sets the match function for @completion to be @func. The match function
447 	 * is used to determine if a row should or should not be in the completion
448 	 * list.
449 	 *
450 	 * Params:
451 	 *     func = the #GtkEntryCompletionMatchFunc to use
452 	 *     funcData = user data for @func
453 	 *     funcNotify = destroy notify for @func_data.
454 	 *
455 	 * Since: 2.4
456 	 */
457 	public void setMatchFunc(GtkEntryCompletionMatchFunc func, void* funcData, GDestroyNotify funcNotify)
458 	{
459 		gtk_entry_completion_set_match_func(gtkEntryCompletion, func, funcData, funcNotify);
460 	}
461 
462 	/**
463 	 * Requires the length of the search key for @completion to be at least
464 	 * @length. This is useful for long lists, where completing using a small
465 	 * key takes a lot of time and will come up with meaningless results anyway
466 	 * (ie, a too large dataset).
467 	 *
468 	 * Params:
469 	 *     length = the minimum length of the key in order to start completing
470 	 *
471 	 * Since: 2.4
472 	 */
473 	public void setMinimumKeyLength(int length)
474 	{
475 		gtk_entry_completion_set_minimum_key_length(gtkEntryCompletion, length);
476 	}
477 
478 	/**
479 	 * Sets the model for a #GtkEntryCompletion. If @completion already has
480 	 * a model set, it will remove it before setting the new model.
481 	 * If model is %NULL, then it will unset the model.
482 	 *
483 	 * Params:
484 	 *     model = the #GtkTreeModel
485 	 *
486 	 * Since: 2.4
487 	 */
488 	public void setModel(TreeModelIF model)
489 	{
490 		gtk_entry_completion_set_model(gtkEntryCompletion, (model is null) ? null : model.getTreeModelStruct());
491 	}
492 
493 	/**
494 	 * Sets whether the completions should be presented in a popup window.
495 	 *
496 	 * Params:
497 	 *     popupCompletion = %TRUE to do popup completion
498 	 *
499 	 * Since: 2.6
500 	 */
501 	public void setPopupCompletion(bool popupCompletion)
502 	{
503 		gtk_entry_completion_set_popup_completion(gtkEntryCompletion, popupCompletion);
504 	}
505 
506 	/**
507 	 * Sets whether the completion popup window will be resized to be the same
508 	 * width as the entry.
509 	 *
510 	 * Params:
511 	 *     popupSetWidth = %TRUE to make the width of the popup the same as the entry
512 	 *
513 	 * Since: 2.8
514 	 */
515 	public void setPopupSetWidth(bool popupSetWidth)
516 	{
517 		gtk_entry_completion_set_popup_set_width(gtkEntryCompletion, popupSetWidth);
518 	}
519 
520 	/**
521 	 * Sets whether the completion popup window will appear even if there is
522 	 * only a single match. You may want to set this to %FALSE if you
523 	 * are using [inline completion][GtkEntryCompletion--inline-completion].
524 	 *
525 	 * Params:
526 	 *     popupSingleMatch = %TRUE if the popup should appear even for a single
527 	 *         match
528 	 *
529 	 * Since: 2.8
530 	 */
531 	public void setPopupSingleMatch(bool popupSingleMatch)
532 	{
533 		gtk_entry_completion_set_popup_single_match(gtkEntryCompletion, popupSingleMatch);
534 	}
535 
536 	/**
537 	 * Convenience function for setting up the most used case of this code: a
538 	 * completion list with just strings. This function will set up @completion
539 	 * to have a list displaying all (and just) strings in the completion list,
540 	 * and to get those strings from @column in the model of @completion.
541 	 *
542 	 * This functions creates and adds a #GtkCellRendererText for the selected
543 	 * column. If you need to set the text column, but don't want the cell
544 	 * renderer, use g_object_set() to set the #GtkEntryCompletion:text-column
545 	 * property directly.
546 	 *
547 	 * Params:
548 	 *     column = the column in the model of @completion to get strings from
549 	 *
550 	 * Since: 2.4
551 	 */
552 	public void setTextColumn(int column)
553 	{
554 		gtk_entry_completion_set_text_column(gtkEntryCompletion, column);
555 	}
556 
557 	protected class OnActionActivatedDelegateWrapper
558 	{
559 		static OnActionActivatedDelegateWrapper[] listeners;
560 		void delegate(int, EntryCompletion) dlg;
561 		gulong handlerId;
562 		
563 		this(void delegate(int, EntryCompletion) dlg)
564 		{
565 			this.dlg = dlg;
566 			this.listeners ~= this;
567 		}
568 		
569 		void remove(OnActionActivatedDelegateWrapper source)
570 		{
571 			foreach(index, wrapper; listeners)
572 			{
573 				if (wrapper.handlerId == source.handlerId)
574 				{
575 					listeners[index] = null;
576 					listeners = std.algorithm.remove(listeners, index);
577 					break;
578 				}
579 			}
580 		}
581 	}
582 
583 	/**
584 	 * Gets emitted when an action is activated.
585 	 *
586 	 * Params:
587 	 *     index = the index of the activated action
588 	 *
589 	 * Since: 2.4
590 	 */
591 	gulong addOnActionActivated(void delegate(int, EntryCompletion) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
592 	{
593 		auto wrapper = new OnActionActivatedDelegateWrapper(dlg);
594 		wrapper.handlerId = Signals.connectData(
595 			this,
596 			"action-activated",
597 			cast(GCallback)&callBackActionActivated,
598 			cast(void*)wrapper,
599 			cast(GClosureNotify)&callBackActionActivatedDestroy,
600 			connectFlags);
601 		return wrapper.handlerId;
602 	}
603 	
604 	extern(C) static void callBackActionActivated(GtkEntryCompletion* entrycompletionStruct, int index, OnActionActivatedDelegateWrapper wrapper)
605 	{
606 		wrapper.dlg(index, wrapper.outer);
607 	}
608 	
609 	extern(C) static void callBackActionActivatedDestroy(OnActionActivatedDelegateWrapper wrapper, GClosure* closure)
610 	{
611 		wrapper.remove(wrapper);
612 	}
613 
614 	protected class OnCursorOnMatchDelegateWrapper
615 	{
616 		static OnCursorOnMatchDelegateWrapper[] listeners;
617 		bool delegate(TreeModelIF, TreeIter, EntryCompletion) dlg;
618 		gulong handlerId;
619 		
620 		this(bool delegate(TreeModelIF, TreeIter, EntryCompletion) dlg)
621 		{
622 			this.dlg = dlg;
623 			this.listeners ~= this;
624 		}
625 		
626 		void remove(OnCursorOnMatchDelegateWrapper source)
627 		{
628 			foreach(index, wrapper; listeners)
629 			{
630 				if (wrapper.handlerId == source.handlerId)
631 				{
632 					listeners[index] = null;
633 					listeners = std.algorithm.remove(listeners, index);
634 					break;
635 				}
636 			}
637 		}
638 	}
639 
640 	/**
641 	 * Gets emitted when a match from the cursor is on a match
642 	 * of the list. The default behaviour is to replace the contents
643 	 * of the entry with the contents of the text column in the row
644 	 * pointed to by @iter.
645 	 *
646 	 * Note that @model is the model that was passed to
647 	 * gtk_entry_completion_set_model().
648 	 *
649 	 * Params:
650 	 *     model = the #GtkTreeModel containing the matches
651 	 *     iter = a #GtkTreeIter positioned at the selected match
652 	 *
653 	 * Returns: %TRUE if the signal has been handled
654 	 *
655 	 * Since: 2.12
656 	 */
657 	gulong addOnCursorOnMatch(bool delegate(TreeModelIF, TreeIter, EntryCompletion) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
658 	{
659 		auto wrapper = new OnCursorOnMatchDelegateWrapper(dlg);
660 		wrapper.handlerId = Signals.connectData(
661 			this,
662 			"cursor-on-match",
663 			cast(GCallback)&callBackCursorOnMatch,
664 			cast(void*)wrapper,
665 			cast(GClosureNotify)&callBackCursorOnMatchDestroy,
666 			connectFlags);
667 		return wrapper.handlerId;
668 	}
669 	
670 	extern(C) static int callBackCursorOnMatch(GtkEntryCompletion* entrycompletionStruct, GtkTreeModel* model, GtkTreeIter* iter, OnCursorOnMatchDelegateWrapper wrapper)
671 	{
672 		return wrapper.dlg(ObjectG.getDObject!(TreeModel, TreeModelIF)(model), ObjectG.getDObject!(TreeIter)(iter), wrapper.outer);
673 	}
674 	
675 	extern(C) static void callBackCursorOnMatchDestroy(OnCursorOnMatchDelegateWrapper wrapper, GClosure* closure)
676 	{
677 		wrapper.remove(wrapper);
678 	}
679 
680 	protected class OnInsertPrefixDelegateWrapper
681 	{
682 		static OnInsertPrefixDelegateWrapper[] listeners;
683 		bool delegate(string, EntryCompletion) dlg;
684 		gulong handlerId;
685 		
686 		this(bool delegate(string, EntryCompletion) dlg)
687 		{
688 			this.dlg = dlg;
689 			this.listeners ~= this;
690 		}
691 		
692 		void remove(OnInsertPrefixDelegateWrapper source)
693 		{
694 			foreach(index, wrapper; listeners)
695 			{
696 				if (wrapper.handlerId == source.handlerId)
697 				{
698 					listeners[index] = null;
699 					listeners = std.algorithm.remove(listeners, index);
700 					break;
701 				}
702 			}
703 		}
704 	}
705 
706 	/**
707 	 * Gets emitted when the inline autocompletion is triggered.
708 	 * The default behaviour is to make the entry display the
709 	 * whole prefix and select the newly inserted part.
710 	 *
711 	 * Applications may connect to this signal in order to insert only a
712 	 * smaller part of the @prefix into the entry - e.g. the entry used in
713 	 * the #GtkFileChooser inserts only the part of the prefix up to the
714 	 * next '/'.
715 	 *
716 	 * Params:
717 	 *     prefix = the common prefix of all possible completions
718 	 *
719 	 * Returns: %TRUE if the signal has been handled
720 	 *
721 	 * Since: 2.6
722 	 */
723 	gulong addOnInsertPrefix(bool delegate(string, EntryCompletion) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
724 	{
725 		auto wrapper = new OnInsertPrefixDelegateWrapper(dlg);
726 		wrapper.handlerId = Signals.connectData(
727 			this,
728 			"insert-prefix",
729 			cast(GCallback)&callBackInsertPrefix,
730 			cast(void*)wrapper,
731 			cast(GClosureNotify)&callBackInsertPrefixDestroy,
732 			connectFlags);
733 		return wrapper.handlerId;
734 	}
735 	
736 	extern(C) static int callBackInsertPrefix(GtkEntryCompletion* entrycompletionStruct, char* prefix, OnInsertPrefixDelegateWrapper wrapper)
737 	{
738 		return wrapper.dlg(Str.toString(prefix), wrapper.outer);
739 	}
740 	
741 	extern(C) static void callBackInsertPrefixDestroy(OnInsertPrefixDelegateWrapper wrapper, GClosure* closure)
742 	{
743 		wrapper.remove(wrapper);
744 	}
745 
746 	protected class OnMatchSelectedDelegateWrapper
747 	{
748 		static OnMatchSelectedDelegateWrapper[] listeners;
749 		bool delegate(TreeModelIF, TreeIter, EntryCompletion) dlg;
750 		gulong handlerId;
751 		
752 		this(bool delegate(TreeModelIF, TreeIter, EntryCompletion) dlg)
753 		{
754 			this.dlg = dlg;
755 			this.listeners ~= this;
756 		}
757 		
758 		void remove(OnMatchSelectedDelegateWrapper source)
759 		{
760 			foreach(index, wrapper; listeners)
761 			{
762 				if (wrapper.handlerId == source.handlerId)
763 				{
764 					listeners[index] = null;
765 					listeners = std.algorithm.remove(listeners, index);
766 					break;
767 				}
768 			}
769 		}
770 	}
771 
772 	/**
773 	 * Gets emitted when a match from the list is selected.
774 	 * The default behaviour is to replace the contents of the
775 	 * entry with the contents of the text column in the row
776 	 * pointed to by @iter.
777 	 *
778 	 * Note that @model is the model that was passed to
779 	 * gtk_entry_completion_set_model().
780 	 *
781 	 * Params:
782 	 *     model = the #GtkTreeModel containing the matches
783 	 *     iter = a #GtkTreeIter positioned at the selected match
784 	 *
785 	 * Returns: %TRUE if the signal has been handled
786 	 *
787 	 * Since: 2.4
788 	 */
789 	gulong addOnMatchSelected(bool delegate(TreeModelIF, TreeIter, EntryCompletion) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
790 	{
791 		auto wrapper = new OnMatchSelectedDelegateWrapper(dlg);
792 		wrapper.handlerId = Signals.connectData(
793 			this,
794 			"match-selected",
795 			cast(GCallback)&callBackMatchSelected,
796 			cast(void*)wrapper,
797 			cast(GClosureNotify)&callBackMatchSelectedDestroy,
798 			connectFlags);
799 		return wrapper.handlerId;
800 	}
801 	
802 	extern(C) static int callBackMatchSelected(GtkEntryCompletion* entrycompletionStruct, GtkTreeModel* model, GtkTreeIter* iter, OnMatchSelectedDelegateWrapper wrapper)
803 	{
804 		return wrapper.dlg(ObjectG.getDObject!(TreeModel, TreeModelIF)(model), ObjectG.getDObject!(TreeIter)(iter), wrapper.outer);
805 	}
806 	
807 	extern(C) static void callBackMatchSelectedDestroy(OnMatchSelectedDelegateWrapper wrapper, GClosure* closure)
808 	{
809 		wrapper.remove(wrapper);
810 	}
811 
812 	protected class OnNoMatchesDelegateWrapper
813 	{
814 		static OnNoMatchesDelegateWrapper[] listeners;
815 		void delegate(EntryCompletion) dlg;
816 		gulong handlerId;
817 		
818 		this(void delegate(EntryCompletion) dlg)
819 		{
820 			this.dlg = dlg;
821 			this.listeners ~= this;
822 		}
823 		
824 		void remove(OnNoMatchesDelegateWrapper source)
825 		{
826 			foreach(index, wrapper; listeners)
827 			{
828 				if (wrapper.handlerId == source.handlerId)
829 				{
830 					listeners[index] = null;
831 					listeners = std.algorithm.remove(listeners, index);
832 					break;
833 				}
834 			}
835 		}
836 	}
837 
838 	/**
839 	 * Gets emitted when the filter model has zero
840 	 * number of rows in completion_complete method.
841 	 * (In other words when GtkEntryCompletion is out of
842 	 * suggestions)
843 	 *
844 	 * Since: 3.14
845 	 */
846 	gulong addOnNoMatches(void delegate(EntryCompletion) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
847 	{
848 		auto wrapper = new OnNoMatchesDelegateWrapper(dlg);
849 		wrapper.handlerId = Signals.connectData(
850 			this,
851 			"no-matches",
852 			cast(GCallback)&callBackNoMatches,
853 			cast(void*)wrapper,
854 			cast(GClosureNotify)&callBackNoMatchesDestroy,
855 			connectFlags);
856 		return wrapper.handlerId;
857 	}
858 	
859 	extern(C) static void callBackNoMatches(GtkEntryCompletion* entrycompletionStruct, OnNoMatchesDelegateWrapper wrapper)
860 	{
861 		wrapper.dlg(wrapper.outer);
862 	}
863 	
864 	extern(C) static void callBackNoMatchesDestroy(OnNoMatchesDelegateWrapper wrapper, GClosure* closure)
865 	{
866 		wrapper.remove(wrapper);
867 	}
868 }