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