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