1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
|
# Copyright 2008 Nanorex, Inc. See LICENSE file for details.
"""
@author: Ninad
@copyright: 2008 Nanorex, Inc. See LICENSE file for details.
@version:$Id$
History:
Created on 2008-11-06
TODO:
Created as a part of a NFR by Mark on Nov 6, 2008. This is a quick implementation
subjected to a number of changes / revisions.
"""
import foundation.env as env
from PyQt4.Qt import QToolButton
from PyQt4.Qt import QPalette
from PyQt4.Qt import QTextOption
from PyQt4.Qt import QLabel
from PyQt4.Qt import QAction, QMenu
from PyQt4.Qt import Qt, SIGNAL
from PM.PM_Colors import getPalette
from PM.PM_Colors import sequenceEditStrandMateBaseColor
from PM.PM_DockWidget import PM_DockWidget
from PM.PM_WidgetRow import PM_WidgetRow
from PM.PM_ToolButton import PM_ToolButton
from PM.PM_ComboBox import PM_ComboBox
from PM.PM_TextEdit import PM_TextEdit
from PM.PM_LineEdit import PM_LineEdit
from PM.PM_PushButton import PM_PushButton
from PM.PM_SpinBox import PM_SpinBox
from PM.PM_SelectionListWidget import PM_SelectionListWidget
from PM.PM_DnaSearchResultTable import PM_DnaSearchResultTable
from utilities.icon_utilities import geticon, getpixmap
from utilities.prefs_constants import dnaSearchTypeLabelChoice_prefs_key
from widgets.prefs_widgets import connect_comboBox_with_pref
_superclass = PM_DockWidget
class SelectNodeByNameDockWidget(PM_DockWidget):
"""
The Ui_DnaSequenceEditor class defines UI elements for the Sequence Editor
object. The sequence editor is usually visible while in DNA edit mode.
It is a DockWidget that is doced at the bottom of the MainWindow
"""
_title = "Select Node by Name"
_groupBoxCount = 0
_lastGroupBox = None
def __init__(self, win):
"""
Constructor for the Ui_DnaSequenceEditor
@param win: The parentWidget (MainWindow) for the sequence editor
"""
self.win = win
parentWidget = win
_superclass.__init__(self, parentWidget, title = self._title)
win.addDockWidget(Qt.BottomDockWidgetArea, self)
self.setFixedHeight(120)
##self.setFixedWidth(90)
self.connect_or_disconnect_signals(True)
if not self.win.selectByNameAction.isChecked():
self.close()
def show(self):
"""
Overrides superclass method.
"""
_superclass.show(self)
val = env.prefs[dnaSearchTypeLabelChoice_prefs_key]
self.searchTypeComboBox_indexChanged(val)
def connect_or_disconnect_signals(self, isConnect):
"""
Connect or disconnect widget signals sent to their slot methods.
This can be overridden in subclasses. By default it does nothing.
@param isConnect: If True the widget will send the signals to the slot
method.
@type isConnect: boolean
"""
if isConnect:
change_connect = self.win.connect
else:
change_connect = self.win.disconnect
self._listWidget.connect_or_disconnect_signals(isConnect)
change_connect( self.searchToolButton,
SIGNAL("clicked()"),
self.searchNodes)
prefs_key = dnaSearchTypeLabelChoice_prefs_key
connect_comboBox_with_pref(self.searchTypeComboBox,
prefs_key )
change_connect( self.searchTypeComboBox,
SIGNAL("currentIndexChanged(int)"),
self.searchTypeComboBox_indexChanged)
def searchTypeComboBox_indexChanged(self, val):
if val == 0:
##self._widgetRow1.show()
##self._widgetRow2.hide()
self._widgetRow1.setEnabled(True)
self._widgetRow2.setEnabled(False)
else:
##self._widgetRow2.show()
##self._widgetRow1.hide()
self._widgetRow2.setEnabled(True)
self._widgetRow1.setEnabled(False)
def searchNodes(self):
"""
ONLY implemented for DnaStrand or DnaSegments.
"""
assy = self.win.assy
topnode = assy.part.topnode
lst = []
def func(node):
if isinstance(node, assy.DnaStrandOrSegment):
lst.append(node)
topnode.apply2all(func)
choice = env.prefs[dnaSearchTypeLabelChoice_prefs_key]
if choice == 0:
nodes = self._searchNodesByName(lst)
elif choice == 1:
nodes = self._searchNodesByNucleotides(lst)
self._listWidget.insertItems(
row = 0,
items = nodes)
def _searchNodesByNucleotides(self, nodeList):
lst = nodeList
min_val = self._nucleotidesSpinBox_1.value()
max_val = self._nucleotidesSpinBox_2.value()
if min_val > max_val:
print "Lower value for number of nucleotides exceeds max search value"
return ()
def func2(node):
n = node.getNumberOfNucleotides()
return (n >= min_val and n <= max_val)
return filter(lambda m:func2(m), lst)
def _searchNodesByName(self, nodeList):
nodeNameString = self.findLineEdit.text()
nodeNameString = str(nodeNameString)
lst = nodeList
def func2(node):
n = len(nodeNameString)
if len(node.name)< n:
return False
nameString = str(node.name[:n])
if nameString.lower() == nodeNameString.lower():
return True
return False
return filter(lambda m:func2(m), lst)
def closeEvent(self, event):
self.win.selectByNameAction.setChecked(False)
_superclass.closeEvent(self, event)
def _loadWidgets(self):
"""
Overrides PM.PM_DockWidget._loadWidgets. Loads the widget in this
dockwidget.
"""
self._loadMenuWidgets()
self._loadTableWidget()
def _loadTableWidget(self):
self._listWidget = PM_DnaSearchResultTable(self, self.win)
def _loadMenuWidgets(self):
"""
Load the various menu widgets (e.g. Open, save sequence options,
Find and replace widgets etc.
"""
#Note: Find and replace widgets might be moved to their own class.
self.searchTypeComboBox = \
PM_ComboBox( self,
label = "Search options:",
choices = ["By node name", "By # of bases (DNA only)"],
setAsDefault = True)
#Find widgets --
self._nucleotidesSpinBox_1 = PM_SpinBox(self,
label = "",
value = 10,
setAsDefault = False,
singleStep = 10,
minimum = 1,
maximum = 50000)
self._nucleotidesSpinBox_2 = PM_SpinBox(self,
label = "",
value = 50,
setAsDefault = False,
singleStep = 10,
minimum = 1,
maximum = 50000)
self.findLineEdit = \
PM_LineEdit( self,
label = "",
spanWidth = False)
self.findLineEdit.setMaximumWidth(80)
self.findOptionsToolButton = PM_ToolButton(self)
self.findOptionsToolButton.setMaximumWidth(12)
self.findOptionsToolButton.setAutoRaise(True)
##self.findOptionsToolButton.setPopupMode(QToolButton.MenuButtonPopup)
##self._setFindOptionsToolButtonMenu()
self.searchToolButton = PM_ToolButton(
self,
iconPath = "ui/actions/Properties Manager/Find_Next.png")
self.searchToolButton.setAutoRaise(False)
self.warningSign = QLabel(self)
self.warningSign.setPixmap(
getpixmap('ui/actions/Properties Manager/Warning.png'))
self.warningSign.hide()
self.phraseNotFoundLabel = QLabel(self)
self.phraseNotFoundLabel.setText("Not Found")
self.phraseNotFoundLabel.hide()
# NOTE: Following needs cleanup in the PM_WidgetRow/ PM_WidgetGrid
# but this explanation is sufficient until thats done --
# When the widget type starts with the word 'PM_' , the
# PM_WidgetRow treats it as a well defined widget and thus doesn't try
# to create a QWidget object (or its subclasses)
# This is the reason why qLabels such as self.warningSign and
# self.phraseNotFoundLabel are defined as PM_Labels and not 'QLabels'
# If they were defined as 'QLabel'(s) then PM_WidgetRow would have
# recreated the label. Since we want to show/hide the above mentioned
# labels (and if they were recreated as mentioned above),
# we would have needed to define those something like this:
# self.phraseNotFoundLabel = widgetRow._widgetList[-2]
#Cleanup in PM_widgetGrid could be to check if the widget starts with
#'Q' instead of 'PM_'
#Widgets to include in the widget row.
widgetList1 = [
('QLabel', " Search for name:", 1),
('PM_LineEdit', self.findLineEdit, 2),
('PM_ToolButton', self.findOptionsToolButton, 3),
('PM_ToolButton', self.searchToolButton, 4),
('PM_Label', self.warningSign, 5),
('PM_Label', self.phraseNotFoundLabel, 6),
('QSpacerItem', 5, 5, 7) ]
widgetList2 = [
('QLabel', " Number of bases: >=", 1),
('PM_SpinBox', self._nucleotidesSpinBox_1, 2),
('QLabel', " <=", 3),
('PM_SpinBox', self._nucleotidesSpinBox_2, 4),
('QSpacerItem', 5, 5, 5)]
widgetList3 = [
('QSpacerItem', 5, 5, 1),
('PM_ToolButton', self.searchToolButton, 2),
('PM_Label', self.warningSign, 3),
('PM_Label', self.phraseNotFoundLabel, 4),
('QSpacerItem', 5, 5, 5) ]
self._widgetRow1 = PM_WidgetRow(self,
title = '',
widgetList = widgetList1,
label = "",
spanWidth = True )
self._widgetRow2 = PM_WidgetRow(self,
title = '',
widgetList = widgetList2,
label = "",
spanWidth = True )
self._widgetRow3 = PM_WidgetRow(self,
title = '',
widgetList = widgetList3,
label = "",
spanWidth = True )
|