1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """Defines a class representing a selection of items the user has selected
17 in a UI."""
18
19 from muntjac.util import OrderedSet
20
21 from muntjac.ui.abstract_field import AbstractField
22 from muntjac.terminal.resource import IResource
23 from muntjac.terminal.key_mapper import KeyMapper
24
25 from muntjac.data import property as prop
26 from muntjac.data import container
27 from muntjac.data import item
28
29 from muntjac.data.util.indexed_container import IndexedContainer
30
31 from muntjac.event.dd.acceptcriteria.target_detail_is import TargetDetailIs
32 from muntjac.event.dd.target_details_impl import TargetDetailsImpl
33
34 from muntjac.event.dd.acceptcriteria.contains_data_flavor import \
35 ContainsDataFlavor
36
37 from muntjac.event.dd.acceptcriteria.client_side_criterion import \
38 ClientSideCriterion
39
40 from muntjac.terminal.gwt.client.ui.dd.vertical_drop_location import \
41 VerticalDropLocation
42
43
44 -class AbstractSelect(AbstractField, container.IContainer, container.IViewer,
45 container.IPropertySetChangeListener,
46 container.IPropertySetChangeNotifier,
47 container.IItemSetChangeNotifier,
48 container.IItemSetChangeListener):
49 """A class representing a selection of items the user has selected
50 in a UI. The set of choices is presented as a set of L{IItem}s in a
51 L{IContainer}.
52
53 A C{Select} component may be in single- or multiselect mode. Multiselect
54 mode means that more than one item can be selected simultaneously.
55
56 @author: Vaadin Ltd.
57 @author: Richard Lincoln
58 @version: 1.1.2
59 """
60
61
62
63 ITEM_CAPTION_MODE_ID = 0
64
65
66
67 ITEM_CAPTION_MODE_ITEM = 1
68
69
70
71
72 ITEM_CAPTION_MODE_INDEX = 2
73
74
75
76
77 ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID = 3
78
79
80 ITEM_CAPTION_MODE_EXPLICIT = 4
81
82
83 ITEM_CAPTION_MODE_ICON_ONLY = 5
84
85
86
87 ITEM_CAPTION_MODE_PROPERTY = 6
88
89
91 """Creates an empty Select with caption, that is connected to a
92 data-source or is filled from a collection of option values.
93
94 @param args: tuple of the form
95 - ()
96 - (caption)
97 1. the caption of the component.
98 - (caption, dataSource)
99 1. the caption of the component.
100 2. the IContainer datasource to be selected from by
101 this select.
102 - (caption, options)
103 1. the caption of the component.
104 2. the Collection containing the options.
105 """
106
107 self._multiSelect = False
108
109
110 self.items = None
111
112
113 self._allowNewOptions = None
114
115
116 self.itemIdMapper = KeyMapper()
117
118
119 self._itemIcons = dict()
120
121
122 self._itemCaptions = dict()
123
124
125 self._itemCaptionMode = self.ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID
126
127
128 self._itemCaptionPropertyId = None
129
130
131 self._itemIconPropertyId = None
132
133
134 self._propertySetEventListeners = OrderedSet()
135
136
137 self._itemSetEventListeners = OrderedSet()
138
139 self._propertySetEventCallbacks = dict()
140
141 self._itemSetEventCallbacks = dict()
142
143
144
145
146
147
148 self._nullSelectionItemId = None
149
150
151 self._nullSelectionAllowed = True
152
153 self._newItemHandler = None
154
155
156 self._captionChangeListener = None
157
158 super(AbstractSelect, self).__init__()
159
160 nargs = len(args)
161 if nargs == 0:
162 self.setContainerDataSource(IndexedContainer())
163 elif nargs == 1:
164 caption, = args
165 self.setContainerDataSource(IndexedContainer())
166 self.setCaption(caption)
167 elif nargs == 2:
168 if isinstance(args[1], list):
169 caption, options = args
170
171 c = IndexedContainer()
172 if options is not None:
173 for o in options:
174 c.addItem(o)
175
176 self.setCaption(caption)
177 self.setContainerDataSource(c)
178 else:
179 caption, dataSource = args
180 self.setCaption(caption)
181 self.setContainerDataSource(dataSource)
182 else:
183 raise ValueError, 'too many arguments'
184
185
186 - def paintContent(self, target):
187 """Paints the content of this component.
188
189 @param target:
190 the Paint Event.
191 @raise PaintException:
192 if the paint operation failed.
193 """
194
195 super(AbstractSelect, self).paintContent(target)
196
197
198 if self.isMultiSelect():
199 target.addAttribute('selectmode', 'multi')
200
201 if self.isNewItemsAllowed():
202 target.addAttribute('allownewitem', True)
203
204 if self.isNullSelectionAllowed():
205 target.addAttribute('nullselect', True)
206 if self.getNullSelectionItemId() is not None:
207 target.addAttribute('nullselectitem', True)
208
209
210 if self.isMultiSelect():
211 selectedKeys = [None] * len(self.getValue())
212 elif (self.getValue() is None
213 and self.getNullSelectionItemId() is None):
214 selectedKeys = [None] * 0
215 else:
216 selectedKeys = [None] * 1
217
218
219 self.getCaptionChangeListener().clear()
220
221
222 target.startTag('options')
223 keyIndex = 0
224
225 ids = self.getItemIds()
226 if (self.isNullSelectionAllowed()
227 and (self.getNullSelectionItemId() is not None)
228 and (self.getNullSelectionItemId() not in ids)):
229 idd = self.getNullSelectionItemId()
230
231 target.startTag('so')
232 self.paintItem(target, idd)
233 if self.isSelected(idd):
234 selectedKeys[keyIndex] = self.itemIdMapper.key(idd)
235 keyIndex += 1
236 target.endTag('so')
237
238 i = self.getItemIds()
239
240 for idd in i:
241 if (not self.isNullSelectionAllowed()
242 and (idd is not None)
243 and (idd == self.getNullSelectionItemId())):
244
245
246 continue
247
248 key = self.itemIdMapper.key(idd)
249
250
251 self.getCaptionChangeListener().addNotifierForItem(idd)
252 target.startTag('so')
253 self.paintItem(target, idd)
254 if self.isSelected(idd) and (keyIndex < len(selectedKeys)):
255 selectedKeys[keyIndex] = key
256 keyIndex += 1
257 target.endTag('so')
258 target.endTag('options')
259
260
261 target.addVariable(self, 'selected', selectedKeys)
262 if self.isNewItemsAllowed():
263 target.addVariable(self, 'newitem', '')
264
265
280
281
358
359
361 """Setter for new item handler that is called when user adds
362 new item in newItemAllowed mode.
363 """
364 self._newItemHandler = newItemHandler
365
366
368 """Getter for new item handler.
369
370 @return: newItemHandler
371 """
372 if self._newItemHandler is None:
373 self._newItemHandler = DefaultNewItemHandler(self)
374 return self._newItemHandler
375
376
378 """Gets the visible item ids. In Select, this returns list of all
379 item ids, but can be overriden in subclasses if they paint only
380 part of the items to the terminal or null if no items is visible.
381 """
382 if self.isVisible():
383 return self.getItemIds()
384 return None
385
386
387 - def getType(self, propertyId=None):
388 """Returns the type of the property. C{getValue} and
389 C{setValue} methods must be compatible with this type:
390 one can safely cast C{getValue} to given type and pass
391 any variable assignable to this type as a parameter to
392 C{setValue}.
393
394 @param propertyId:
395 the Id identifying the property.
396 @return: the Type of the property.
397 @see: L{IContainer.getType}
398 """
399 if propertyId is None:
400 if self.isMultiSelect():
401 return set
402 else:
403 return object
404 else:
405 return self.items.getType(propertyId)
406
407
409 """Gets the selected item id or in multiselect mode a set of
410 selected ids.
411
412 @see: L{AbstractField.getValue}
413 """
414 retValue = super(AbstractSelect, self).getValue()
415
416 if self.isMultiSelect():
417
418
419 if retValue is None:
420 return set()
421
422 if isinstance(retValue, set):
423 return retValue
424
425 elif isinstance(retValue, list):
426 return set(retValue)
427
428 else:
429 s = set()
430 if self.items.containsId(retValue):
431 s.add(retValue)
432 return s
433 else:
434 return retValue
435
436
437 - def setValue(self, newValue, repaintIsNotNeeded=None):
438 """Sets the visible value of the property.
439
440 The value of the select is the selected item id. If the select
441 is in multiselect-mode, the value is a set of selected item keys.
442 In multiselect mode all collections of id:s can be assigned.
443
444 @param newValue:
445 the New selected item or collection of selected items.
446 @param repaintIsNotNeeded:
447 True if caller is sure that repaint is not needed.
448 @see: L{AbstractField.setValue}
449 """
450 if repaintIsNotNeeded is None:
451 if newValue == self.getNullSelectionItemId():
452 newValue = None
453 self.setValue(newValue, False)
454 else:
455 if self.isMultiSelect():
456
457 if newValue is None:
458 super(AbstractSelect, self).setValue(set(),
459 repaintIsNotNeeded)
460 elif hasattr(newValue, '__iter__'):
461 super(AbstractSelect, self).setValue(set(newValue),
462 repaintIsNotNeeded)
463
464 elif (newValue is None) or (self.items.containsId(newValue)):
465 super(AbstractSelect, self).setValue(newValue,
466 repaintIsNotNeeded)
467
468
469
471 """Gets the item from the container with given id. If the container
472 does not contain the requested item, null is returned.
473
474 @param itemId:
475 the item id.
476 @return: the item from the container.
477 """
478 return self.items.getItem(itemId)
479
480
482 """Gets the item Id collection from the container.
483
484 @return: the Collection of item ids.
485 """
486 return self.items.getItemIds()
487
488
490 """Gets the property Id collection from the container.
491
492 @return: the Collection of property ids.
493 """
494 return self.items.getContainerPropertyIds()
495
496
497
498
499
500
502 return len(self.items)
503
504
507
508
510 """Tests, if the collection contains an item with given id.
511
512 @param itemId:
513 the Id the of item to be tested.
514 """
515 if itemId is not None:
516 return self.items.containsId(itemId)
517 else:
518 return False
519
520
522 """Gets the IProperty identified by the given itemId and propertyId
523 from the IContainer
524
525 @see: L{IContainer.getContainerProperty}
526 """
527 return self.items.getContainerProperty(itemId, propertyId)
528
529
531 """Adds the new property to all items. Adds a property with given
532 id, type and default value to all items in the container.
533
534 This functionality is optional. If the function is unsupported,
535 it always returns false.
536
537 @return: True if the operation succeeded.
538 @see: L{IContainer.addContainerProperty}
539 """
540 retval = self.items.addContainerProperty(propertyId, typ,
541 defaultValue)
542
543 if (retval and (not isinstance(self.items,
544 container.IPropertySetChangeNotifier))):
545 self.firePropertySetChange()
546
547 return retval
548
549
551 """Removes all items from the container.
552
553 This functionality is optional. If the function is unsupported,
554 it always returns false.
555
556 @return: True if the operation succeeded.
557 @see: L{IContainer.removeAllItems}
558 """
559 retval = self.items.removeAllItems()
560 self.itemIdMapper.removeAll()
561
562 if retval:
563 self.setValue(None)
564 if not isinstance(self.items, container.IItemSetChangeNotifier):
565 self.fireItemSetChange()
566
567 return retval
568
569
571 """Create a new item into container. The created new item is returned
572 and ready for setting property values. if the creation fails, null
573 is returned. In case the container already contains the item, null
574 is returned.
575
576 This functionality is optional. If the function is unsupported, it
577 always returns null.
578
579 @param itemId:
580 the Identification of the item to be created.
581 @return: the Created item with the given id, or null in case of
582 failure.
583 @see: L{IContainer.addItem}
584 """
585 if itemId is None:
586 retval = self.items.addItem()
587 if (retval is not None) and (not isinstance(self.items,
588 container.IItemSetChangeNotifier)):
589 self.fireItemSetChange()
590 return retval
591 else:
592 retval = self.items.addItem(itemId)
593 if (retval is not None) and (not isinstance(self.items,
594 container.IItemSetChangeNotifier)):
595 self.fireItemSetChange()
596 return retval
597
598
607
608
610 """Removes the property from all items. Removes a property with
611 given id from all the items in the container.
612
613 This functionality is optional. If the function is unsupported,
614 it always returns false.
615
616 @return: True if the operation succeeded.
617 @see: L{IContainer.removeContainerProperty}
618 """
619 retval = self.items.removeContainerProperty(propertyId)
620 if retval and (not isinstance(self.items,
621 container.IPropertySetChangeNotifier)):
622 self.firePropertySetChange()
623 return retval
624
625
678
679
681 """Gets the viewing data-source container.
682
683 @see: L{muntjac.data.container.IViewer.getContainerDataSource}
684 """
685 return self.items
686
687
688
690 """Is the select in multiselect mode? In multiselect mode
691
692 @return: the Value of property multiSelect.
693 """
694 return self._multiSelect
695
696
698 """Sets the multiselect mode. Setting multiselect mode false may
699 loose selection information: if selected items set contains one
700 or more selected items, only one of the selected items is kept as
701 selected.
702
703 @param multiSelect:
704 the New value of property multiSelect.
705 """
706 if multiSelect and (self.getNullSelectionItemId() is not None):
707 raise ValueError, ('Multiselect and NullSelectionItemId can '
708 'not be set at the same time.')
709
710 if multiSelect != self._multiSelect:
711
712
713 oldValue = self.getValue()
714
715 self._multiSelect = multiSelect
716
717
718 if multiSelect:
719 s = set()
720 if oldValue is not None:
721 s.add(oldValue)
722
723 self.setValue(s)
724 else:
725 s = oldValue
726 if (s is None) or (len(s) == 0):
727 self.setValue(None)
728 else:
729
730
731 self.setValue(s[0])
732
733 self.requestRepaint()
734
735
737 """Does the select allow adding new options by the user. If true,
738 the new options can be added to the IContainer. The text entered by
739 the user is used as id. Note that data-source must allow adding new
740 items.
741
742 @return: True if additions are allowed.
743 """
744 return self._allowNewOptions
745
746
748 """Enables or disables possibility to add new options by the user.
749
750 @param allowNewOptions:
751 the New value of property allowNewOptions.
752 """
753
754 if self._allowNewOptions != allowNewOptions:
755
756 self._allowNewOptions = allowNewOptions
757
758 self.requestRepaint()
759
760
762 """Override the caption of an item. Setting caption explicitly
763 overrides id, item and index captions.
764
765 @param itemId:
766 the id of the item to be re-captioned.
767 @param caption:
768 the New caption.
769 """
770 if itemId is not None:
771 self._itemCaptions[itemId] = caption
772 self.requestRepaint()
773
774
821
822
824 """Sets the icon for an item.
825
826 @param itemId:
827 the id of the item to be assigned an icon.
828 @param icon:
829 the icon to use or null.
830 """
831 if itemId is not None:
832 if icon is None:
833 if itemId in self._itemIcons:
834 del self._itemIcons[itemId]
835 else:
836 self._itemIcons[itemId] = icon
837 self.requestRepaint()
838
839
841 """Gets the item icon.
842
843 @param itemId:
844 the id of the item to be assigned an icon.
845 @return: the icon for the item or null, if not specified.
846 """
847 explicit = self._itemIcons.get(itemId)
848 if explicit is not None:
849 return explicit
850
851 if self.getItemIconPropertyId() is None:
852 return None
853
854 ip = self.getContainerProperty(itemId, self.getItemIconPropertyId())
855 if ip is None:
856 return None
857
858 icon = ip.getValue()
859 if isinstance(icon, IResource):
860 return icon
861
862 return None
863
864
866 """Sets the item caption mode.
867
868 The mode can be one of the following ones:
869
870 - C{ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID} : Items
871 Id-objects C{toString} is used as item caption. If caption
872 is explicitly specified, it overrides the id-caption.
873 - C{ITEM_CAPTION_MODE_ID} : Items Id-objects
874 C{toString} is used as item caption.
875 - C{ITEM_CAPTION_MODE_ITEM} : IItem-objects
876 C{toString} is used as item caption.
877 - C{ITEM_CAPTION_MODE_INDEX} : The index of the item is
878 used as item caption. The index mode can only be used with the
879 containers implementing C{IContainer.IIndexed} interface.
880 - C{ITEM_CAPTION_MODE_EXPLICIT} : The item captions must
881 be explicitly specified.
882 - C{ITEM_CAPTION_MODE_PROPERTY} : The item captions are
883 read from property, that must be specified with
884 C{setItemCaptionPropertyId}.
885
886 The C{ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID} is the default
887 mode.
888
889 @param mode:
890 the One of the modes listed above.
891 """
892 if ((self.ITEM_CAPTION_MODE_ID <= mode)
893 and (mode <= self.ITEM_CAPTION_MODE_PROPERTY)):
894 self._itemCaptionMode = mode
895 self.requestRepaint()
896
897
899 """Gets the item caption mode.
900
901 The mode can be one of the following ones:
902
903 - C{ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID} : Items
904 Id-objects C{toString} is used as item caption. If caption
905 is explicitly specified, it overrides the id-caption.
906 - C{ITEM_CAPTION_MODE_ID} : Items Id-objects
907 C{toString} is used as item caption.
908 - C{ITEM_CAPTION_MODE_ITEM} : IItem-objects
909 C{toString} is used as item caption.
910 - C{ITEM_CAPTION_MODE_INDEX} : The index of the item is
911 used as item caption. The index mode can only be used with the
912 containers implementing C{IContainer.IIndexed} interface.
913 - C{ITEM_CAPTION_MODE_EXPLICIT} : The item captions must
914 be explicitly specified.
915 - C{ITEM_CAPTION_MODE_PROPERTY} : The item captions are
916 read from property, that must be specified with
917 C{setItemCaptionPropertyId}.
918
919 The C{ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID} is the default
920 mode.
921
922 @return: the One of the modes listed above.
923 """
924 return self._itemCaptionMode
925
926
928 """Sets the item caption property.
929
930 Setting the id to a existing property implicitly sets the item caption
931 mode to C{ITEM_CAPTION_MODE_PROPERTY}. If the object is in
932 C{ITEM_CAPTION_MODE_PROPERTY} mode, setting caption property
933 id null resets the item caption mode to
934 C{ITEM_CAPTION_EXPLICIT_DEFAULTS_ID}.
935
936 Setting the property id to null disables this feature. The id is null
937 by default.
938
939 @param propertyId:
940 the id of the property.
941 """
942 if propertyId is not None:
943 self._itemCaptionPropertyId = propertyId
944 self.setItemCaptionMode(self.ITEM_CAPTION_MODE_PROPERTY)
945 self.requestRepaint()
946 else:
947 self._itemCaptionPropertyId = None
948 if self.getItemCaptionMode() == self.ITEM_CAPTION_MODE_PROPERTY:
949 self.setItemCaptionMode(
950 self.ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID)
951 self.requestRepaint()
952
953
955 """Gets the item caption property.
956
957 @return: the Id of the property used as item caption source.
958 """
959 return self._itemCaptionPropertyId
960
961
963 """Sets the item icon property.
964
965 If the property id is set to a valid value, each item is given an
966 icon got from the given property of the items. The type of the
967 property must be assignable to IResource.
968
969 Note: The icons set with C{setItemIcon} function override
970 the icons from the property.
971
972 Setting the property id to null disables this feature. The id is
973 null by default.
974
975 @param propertyId:
976 the id of the property that specifies icons for items
977 or null
978 @raise ValueError:
979 If the propertyId is not in the container or is not of
980 a valid type
981 """
982 if propertyId is None:
983 self._itemIconPropertyId = None
984
985 elif propertyId not in self.getContainerPropertyIds():
986 raise ValueError, 'IProperty id not found in the container'
987
988 elif issubclass(self.getType(propertyId), IResource):
989 self._itemIconPropertyId = propertyId
990 else:
991 raise ValueError, 'IProperty type must be assignable to IResource'
992
993 self.requestRepaint()
994
995
997 """Gets the item icon property.
998
999 If the property id is set to a valid value, each item is given an
1000 icon got from the given property of the items. The type of the
1001 property must be assignable to Icon.
1002
1003 Note: The icons set with C{setItemIcon} function override
1004 the icons from the property.
1005
1006 Setting the property id to null disables this feature. The id is null
1007 by default.
1008
1009 @return: the Id of the property containing the item icons.
1010 """
1011 return self._itemIconPropertyId
1012
1013
1015 """Tests if an item is selected.
1016
1017 In single select mode testing selection status of the item identified
1018 by L{getNullSelectionItemId} returns true if the value of the
1019 property is null.
1020
1021 @param itemId:
1022 the Id the of the item to be tested.
1023 @see: L{getNullSelectionItemId}
1024 @see: L{setNullSelectionItemId}
1025 """
1026 if itemId is None:
1027 return False
1028
1029 if self.isMultiSelect():
1030 return itemId in self.getValue()
1031 else:
1032 value = self.getValue()
1033 if value is None:
1034 return itemId == self.getNullSelectionItemId()
1035 else:
1036 return itemId == value
1037
1038
1040 """Selects an item.
1041
1042 In single select mode selecting item identified by
1043 L{getNullSelectionItemId} sets the value of the property
1044 to null.
1045
1046 @param itemId:
1047 the identifier of IItem to be selected.
1048 @see: L{getNullSelectionItemId}
1049 @see: L{setNullSelectionItemId}
1050 """
1051 if not self.isMultiSelect():
1052 self.setValue(itemId)
1053 elif (not self.isSelected(itemId) and (itemId is not None)
1054 and self.items.containsId(itemId)):
1055 s = set(self.getValue())
1056 s.add(itemId)
1057 self.setValue(s)
1058
1059
1061 """Unselects an item.
1062
1063 @param itemId:
1064 the identifier of the IItem to be unselected.
1065 @see: L{getNullSelectionItemId}
1066 @see: L{setNullSelectionItemId}
1067 """
1068 if self.isSelected(itemId):
1069 if self.isMultiSelect():
1070 s = set(self.getValue())
1071 s.remove(itemId)
1072 self.setValue(s)
1073 else:
1074 self.setValue(None)
1075
1076
1078 """Notifies this listener that the Containers contents has changed.
1079
1080 @see: L{IPropertySetChangeListener.containerPropertySetChange}
1081 """
1082 self.firePropertySetChange()
1083
1084
1105
1106
1107 - def addCallback(self, callback, eventType=None, *args):
1121
1122
1142
1143
1145 if eventType is None:
1146 eventType = callback._eventType
1147
1148 if issubclass(eventType, container.IItemSetChangeEvent):
1149 if callback in self._itemSetEventCallbacks:
1150 del self._itemSetEventCallbacks[callback]
1151
1152 elif eventType == container.IPropertySetChangeEvent:
1153 if callback in self._propertySetEventCallbacks:
1154 del self._propertySetEventCallbacks[callback]
1155
1156 else:
1157 super(AbstractSelect, self).removeCallback(callback, eventType)
1158
1159
1168
1169
1171 """Lets the listener know a Containers IItem set has changed.
1172
1173 @see: L{IItemSetChangeListener.containerItemSetChange}
1174 """
1175
1176 self.itemIdMapper.removeAll()
1177
1178
1179 self.fireItemSetChange()
1180
1181
1193
1194
1206
1207
1209 """For multi-selectable fields, also an empty collection of values
1210 is considered to be an empty field.
1211
1212 @see: L{AbstractField.isEmpty}.
1213 """
1214 if not self._multiSelect:
1215 return super(AbstractSelect, self).isEmpty()
1216 else:
1217 value = self.getValue()
1218 return (super(AbstractSelect, self).isEmpty()
1219 or (isinstance(value, list) and len(value) == 0))
1220
1221
1223 """Allow or disallow empty selection by the user. If the select is
1224 in single-select mode, you can make an item represent the empty
1225 selection by calling C{setNullSelectionItemId()}. This
1226 way you can for instance set an icon and caption for the null
1227 selection item.
1228
1229 @param nullSelectionAllowed:
1230 whether or not to allow empty selection
1231 @see: L{setNullSelectionItemId}
1232 @see: L{isNullSelectionAllowed}
1233 """
1234 if nullSelectionAllowed != self._nullSelectionAllowed:
1235 self._nullSelectionAllowed = nullSelectionAllowed
1236 self.requestRepaint()
1237
1238
1240 """Checks if null empty selection is allowed by the user.
1241
1242 @return: whether or not empty selection is allowed
1243 @see: L{setNullSelectionAllowed}
1244 """
1245 return self._nullSelectionAllowed
1246
1247
1249 """Returns the item id that represents null value of this select in
1250 single select mode.
1251
1252 Data interface does not support nulls as item ids. Selecting the item
1253 identified by this id is the same as selecting no items at all. This
1254 setting only affects the single select mode.
1255
1256 @return: the Object Null value item id.
1257 @see: L{setNullSelectionItemId}
1258 @see: L{isSelected}
1259 @see: L{select}
1260 """
1261 return self._nullSelectionItemId
1262
1263
1265 """Sets the item id that represents null value of this select.
1266
1267 Data interface does not support nulls as item ids. Selecting the
1268 item identified by this id is the same as selecting no items at all.
1269 This setting only affects the single select mode.
1270
1271 @param nullSelectionItemId:
1272 the nullSelectionItemId to set.
1273 @see: L{getNullSelectionItemId}
1274 @see: L{isSelected}
1275 @see: L{select}
1276 """
1277 if (nullSelectionItemId is not None) and self.isMultiSelect():
1278 raise ValueError, ('Multiselect and NullSelectionItemId can '
1279 'not be set at the same time.')
1280
1281 self._nullSelectionItemId = nullSelectionItemId
1282
1283
1285 """Notifies the component that it is connected to an application.
1286
1287 @see: L{AbstractField.attach}
1288 """
1289 super(AbstractSelect, self).attach()
1290
1291
1299
1300
1302 if self._captionChangeListener is None:
1303 self._captionChangeListener = CaptionChangeListener(self)
1304 return self._captionChangeListener
1305
1308 """Interface for option filtering, used to filter options based on
1309 user entered value. The value is matched to the item caption.
1310 C{FILTERINGMODE_OFF} (0) turns the filtering off.
1311 C{FILTERINGMODE_STARTSWITH} (1) matches from the start of
1312 the caption. C{FILTERINGMODE_CONTAINS} (1) matches anywhere
1313 in the caption.
1314 """
1315
1316 FILTERINGMODE_OFF = 0
1317
1318 FILTERINGMODE_STARTSWITH = 1
1319
1320 FILTERINGMODE_CONTAINS = 2
1321
1323 """Sets the option filtering mode.
1324
1325 @param filteringMode:
1326 the filtering mode to use
1327 """
1328 raise NotImplementedError
1329
1330
1332 """Gets the current filtering mode.
1333
1334 @return: the filtering mode in use
1335 """
1336 raise NotImplementedError
1337
1340 """Multi select modes that controls how multi select behaves."""
1341
1342
1343 DEFAULT = 'DEFAULT'
1344
1345
1346 SIMPLE = 'SIMPLE'
1347
1348 _values = [DEFAULT, SIMPLE]
1349
1350 @classmethod
1353
1354 @classmethod
1357
1360
1362 raise NotImplementedError
1363
1366 """This is a default class that handles adding new items that are typed
1367 by user to selects container.
1368
1369 By extending this class one may implement some logic on new item
1370 addition like database inserts.
1371 """
1372
1375
1401
1404 """Implementation of item set change event."""
1405
1408
1409
1411 """Gets the IProperty where the event occurred.
1412
1413 @see: L{muntjac.data.container.IItemSetChangeEvent.getContainer}
1414 """
1415 return self._container
1416
1419 """Implementation of property set change event."""
1420
1423
1424
1426 """Retrieves the IContainer whose contents have been modified.
1427
1428 @see: L{muntjac.data.container.IPropertySetChangeEvent.getContainer}
1429 """
1430 return self._container
1431
1434 """TargetDetails implementation for subclasses of L{AbstractSelect}
1435 that implement L{DropTarget}.
1436 """
1437
1438 - def __init__(self, rawVariables, select):
1439 """Constructor that automatically converts itemIdOver key to
1440 corresponding item Id
1441 """
1442 super(AbstractSelectTargetDetails, self).__init__(rawVariables, select)
1443
1444
1445 self.idOver = None
1446
1447
1448 keyover = self.getData('itemIdOver')
1449 if keyover is not None:
1450 self.idOver = select.itemIdMapper.get(keyover)
1451
1452
1454 """If the drag operation is currently over an L{IItem}, this
1455 method returns the identifier of that L{IItem}.
1456 """
1457 return self.idOver
1458
1459
1461 """Returns a detailed vertical location where the drop happened on
1462 IItem.
1463 """
1464 detail = self.getData('detail')
1465 if detail is None:
1466 return None
1467 return VerticalDropLocation.valueOf(detail)
1468
1472 """This is a listener helper for IItem and IProperty changes that should
1473 cause a repaint. It should be attached to all items that are displayed,
1474 and the default implementation does this in paintContent(). Especially
1475 "lazyloading" components should take care to add and remove listeners as
1476 appropriate. Call addNotifierForItem() for each painted item (and
1477 remember to clear).
1478
1479 NOTE: singleton, use getCaptionChangeListener().
1480 """
1481
1483 self._select = select
1484
1485
1486
1487 self._captionChangeNotifiers = set()
1488
1489
1519
1520
1530
1531
1534
1535
1538
1541 """Abstract helper class to implement item id based criterion.
1542
1543 Note, inner class used not to open itemIdMapper for public access.
1544 """
1545
1547 if (self.itemIds is None) or (select is None):
1548 raise ValueError, 'Accepted item identifiers must be accepted.'
1549 self.itemIds = set(itemId)
1550 self.select = select
1551
1552
1553 - def paintContent(self, target):
1554 super(AbstractItemSetCriterion, self).paintContent(target)
1555 keys = [None] * len(self.itemIds)
1556
1557 for i, itemId in enumerate(self.itemIds):
1558 key = self.select.itemIdMapper.key(itemId)
1559 keys[i] = key
1560
1561 target.addAttribute('keys', keys)
1562 target.addAttribute('s', self.select)
1563
1566 """Criterion which accepts a drop only if the drop target is (one of)
1567 the given IItem identifier(s). Criterion can be used only on a drop
1568 targets that extends AbstractSelect like L{Table} and L{Tree}.
1569 The target and identifiers of valid Items are given in constructor.
1570 """
1571
1573 """@param select:
1574 the select implementation that is used as a drop target
1575 @param itemId:
1576 the identifier(s) that are valid drop locations
1577 """
1578 super(TargetItemIs, self).__init__(select, itemId)
1579
1580
1581 - def accept(self, dragEvent):
1586
1589 """This criterion accepts a only a L{Transferable} that contains
1590 given IItem (practically its identifier) from a specific AbstractSelect.
1591 """
1592
1594 """@param select:
1595 the select from which the item id's are checked
1596 @param itemId:
1597 the item identifier(s) of the select that are accepted
1598 """
1599 super(AcceptItem, self).__init__(select, itemId)
1600
1601
1602 - def accept(self, dragEvent):
1609
1610
1611
1612
1613
1614 ALL = ContainsDataFlavor('itemId')
1615
1618 """An accept criterion to accept drops only on a specific vertical
1619 location of an item.
1620
1621 This accept criterion is currently usable in Tree and Table
1622 implementations.
1623 """
1624
1625 TOP = None
1626 BOTTOM = None
1627 MIDDLE = None
1628
1631
1632 VerticalLocationIs.TOP = VerticalLocationIs(VerticalDropLocation.TOP)
1633 VerticalLocationIs.BOTTOM = VerticalLocationIs(VerticalDropLocation.BOTTOM)
1634 VerticalLocationIs.MIDDLE = VerticalLocationIs(VerticalDropLocation.MIDDLE)
1638 """Implement this interface and pass it to Tree.setItemDescriptionGenerator
1639 or Table.setItemDescriptionGenerator to generate mouse over descriptions
1640 ("tooltips") for the rows and cells in Table or for the items in Tree.
1641 """
1642
1644 """Called by Table when a cell (and row) is painted or a item is
1645 painted in Tree
1646
1647 @param source:
1648 The source of the generator, the Tree or Table the
1649 generator is attached to
1650 @param itemId:
1651 The itemId of the painted cell
1652 @param propertyId:
1653 The propertyId of the cell, null when getting row
1654 description
1655 @return: The description or "tooltip" of the item.
1656 """
1657 raise NotImplementedError
1658