77 Qt , QTimer , QSortFilterProxyModel , QItemSelection , QItemSelectionModel ,
88 QMimeData , QAbstractItemModel
99)
10+ from AnyQt .QtGui import QDrag
1011
1112from Orange .data import Domain , Variable
1213from Orange .widgets import gui , widget
@@ -50,6 +51,10 @@ class VariablesListItemModel(VariableListModel):
5051 """
5152 MIME_TYPE = "application/x-Orange-VariableListModelData"
5253
54+ def __init__ (self , * args , primitive = False , ** kwargs ):
55+ super ().__init__ (* args , ** kwargs )
56+ self .primitive = primitive
57+
5358 def flags (self , index ):
5459 flags = super ().flags (index )
5560 if index .isValid ():
@@ -97,7 +102,76 @@ def dropMimeData(self, mime, action, row, column, parent):
97102 if row < 0 :
98103 row = self .rowCount ()
99104
105+ if self .primitive and not all (var .is_primitive () for var in variables ):
106+ variables = [var for var in variables if var .is_primitive ()]
107+ self [row :row ] = variables
108+ mime .setProperty ("_moved" , variables )
109+ return False
110+
100111 self [row :row ] = variables
112+ mime .setProperty ("_moved" , True )
113+ return True
114+
115+
116+ class SelectListItemView (VariablesListItemView ):
117+ """
118+ VariableListItemView that accepts information on what has been dropped
119+
120+ At the end of the drag action, only dropped items (i.e. accepted by the
121+ target) are removed.
122+ """
123+ def startDrag (self , supported_actions ):
124+ indexes = self .selectedIndexes ()
125+ if len (indexes ) == 0 :
126+ return
127+ data = self .model ().mimeData (indexes )
128+ if not data :
129+ return
130+ drag = QDrag (self )
131+ drag .setMimeData (data )
132+ drag .exec (supported_actions , self .defaultDropAction ())
133+
134+ moved = data .property ("_moved" )
135+ if moved is None :
136+ return
137+
138+ if moved is True :
139+ # A quicker path if everyhing is moved
140+ for index in self .selectionModel ().selection ():
141+ self .model ().removeRows (index .top (),
142+ index .bottom () - index .top () + 1 )
143+ else :
144+ moved = set (moved )
145+ for row in sorted ((ind .row ()
146+ for ind in self .selectionModel ().selectedIndexes ()
147+ if ind .data (gui .TableVariable ) in moved ),
148+ reverse = True ):
149+ self .model ().removeRows (row , 1 )
150+
151+
152+ class FeatureListItemView (SelectListItemView ):
153+ """
154+ A SelectListItemView whose acceptsDropEvent checks if there are any
155+ primitive variables. Derived from a class that would reject the drop
156+ if there are any non-primitive.
157+ """
158+ def acceptsDropEvent (self , event ):
159+ """Should the drop event be accepted?"""
160+ # Overridden to allow drops if some, not necessarily all variable types match
161+ # disallow drag/drops between windows
162+ if event .source () is not None and \
163+ event .source ().window () is not self .window ():
164+ return False
165+
166+ mime = event .mimeData ()
167+ vars = mime .property ('_items' )
168+ if vars is None :
169+ return False
170+
171+ if not any (var .is_primitive for var in vars ):
172+ return False
173+
174+ event .accept ()
101175 return True
102176
103177
@@ -217,7 +291,9 @@ def update_on_change(view):
217291
218292 self .available_attrs = VariablesListItemModel ()
219293 filter_edit , self .available_attrs_view = variables_filter (
220- parent = self , model = self .available_attrs )
294+ parent = self , model = self .available_attrs ,
295+ view_type = SelectListItemView
296+ )
221297 box .layout ().addWidget (filter_edit )
222298 self .view_boxes .append ((name , box , self .available_attrs_view ))
223299 filter_edit .textChanged .connect (self .__var_counts_update_timer .start )
@@ -236,11 +312,12 @@ def dropcompleted(action):
236312 # 3rd column
237313 name = "Features"
238314 box = gui .vBox (self .controlArea , name , addToLayout = False )
239- self .used_attrs = VariablesListItemModel ()
315+ self .used_attrs = VariablesListItemModel (primitive = True )
240316 filter_edit , self .used_attrs_view = variables_filter (
241317 parent = self , model = self .used_attrs ,
242318 accepted_type = (Orange .data .DiscreteVariable ,
243- Orange .data .ContinuousVariable ))
319+ Orange .data .ContinuousVariable ),
320+ view_type = FeatureListItemView )
244321 self .used_attrs .rowsInserted .connect (self .__used_attrs_changed )
245322 self .used_attrs .rowsRemoved .connect (self .__used_attrs_changed )
246323 self .used_attrs_view .selectionModel ().selectionChanged .connect (
@@ -263,9 +340,9 @@ def dropcompleted(action):
263340 name = "Target"
264341 box = gui .vBox (self .controlArea , name , addToLayout = False )
265342 self .class_attrs = VariablesListItemModel ()
266- self .class_attrs_view = VariablesListItemView (
343+ self .class_attrs_view = SelectListItemView (
267344 acceptedType = (Orange .data .DiscreteVariable ,
268- Orange .data .ContinuousVariable )
345+ Orange .data .ContinuousVariable ),
269346 )
270347 self .class_attrs_view .setModel (self .class_attrs )
271348 self .class_attrs_view .selectionModel ().selectionChanged .connect (
@@ -279,8 +356,9 @@ def dropcompleted(action):
279356 name = "Metas"
280357 box = gui .vBox (self .controlArea , name , addToLayout = False )
281358 self .meta_attrs = VariablesListItemModel ()
282- self .meta_attrs_view = VariablesListItemView (
283- acceptedType = Orange .data .Variable )
359+ self .meta_attrs_view = SelectListItemView (
360+ acceptedType = Orange .data .Variable ,
361+ )
284362 self .meta_attrs_view .setModel (self .meta_attrs )
285363 self .meta_attrs_view .selectionModel ().selectionChanged .connect (
286364 partial (update_on_change , self .meta_attrs_view ))
0 commit comments