##// END OF EJS Templates
Added more documentation for MagicHelper.
Dimitry Kloper -
Show More
@@ -1,163 +1,216 b''
1 """Magic Helper - dockable widget showing magic commands for the MainWindow
1 """MagicHelper - dockable widget showing magic commands for the MainWindow
2 2
3 3
4 4 Authors:
5 5
6 6 * Dimitry Kloper
7 7
8 8 """
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Imports
12 12 #-----------------------------------------------------------------------------
13 13
14 14 # stdlib imports
15 15 import json
16 16 import re
17 17 import sys
18 18
19 19 # System library imports
20 20 from IPython.external.qt import QtGui,QtCore
21 21
22 22 from IPython.core.magic import magic_escapes
23 23
24 24 class MagicHelper(QtGui.QDockWidget):
25 """MagicHelper - dockable widget for convenient search and running of
26 magic command for IPython QtConsole.
27 """
28
29 #---------------------------------------------------------------------------
30 # signals
31 #---------------------------------------------------------------------------
25 32
26 33 pasteRequested = QtCore.pyqtSignal(str, name = 'pasteRequested')
34 """This signal is emitted when user wants to paste selected magic
35 command into the command line.
36 """
37
27 38 runRequested = QtCore.pyqtSignal(str, name = 'runRequested')
39 """This signal is emitted when user wants to execute selected magic command
40 """
41
28 42 readyForUpdate = QtCore.pyqtSignal(name = 'readyForUpdate')
43 """This signal is emitted when MagicHelper is ready to be populated.
44 Since kernel querying mechanisms are out of scope of this class,
45 it expects its owner to invoke MagicHelper.populate_magic_helper()
46 as a reaction on this event.
47 """
29 48
30 49 #---------------------------------------------------------------------------
31 # 'object' interface
50 # constructor
32 51 #---------------------------------------------------------------------------
33 52
34 53 def __init__(self, name, parent):
35
36 54 super(MagicHelper, self).__init__(name, parent)
37 55
38 56 self.data = None
39 57
40 58 class MinListWidget(QtGui.QListWidget):
59 """Temp class to overide the default QListWidget size hint
60 in order to make MagicHelper narrow
61 """
41 62 def sizeHint(self):
42 63 s = QtCore.QSize()
43 64 s.setHeight(super(MinListWidget,self).sizeHint().height())
44 65 s.setWidth(self.sizeHintForColumn(0))
45 66 return s
46 67
68 # construct content
47 69 self.frame = QtGui.QFrame()
48 70 self.search_label = QtGui.QLabel("Search:")
49 71 self.search_line = QtGui.QLineEdit()
50 72 self.search_class = QtGui.QComboBox()
51 73 self.search_list = MinListWidget()
52 74 self.paste_button = QtGui.QPushButton("Paste")
53 75 self.run_button = QtGui.QPushButton("Run")
54 76
77 # layout all the widgets
55 78 main_layout = QtGui.QVBoxLayout()
56 79 search_layout = QtGui.QHBoxLayout()
57 80 search_layout.addWidget(self.search_label)
58 81 search_layout.addWidget(self.search_line, 10)
59 82 main_layout.addLayout(search_layout)
60 83 main_layout.addWidget(self.search_class)
61 84 main_layout.addWidget(self.search_list, 10)
62 85 action_layout = QtGui.QHBoxLayout()
63 86 action_layout.addWidget(self.paste_button)
64 87 action_layout.addWidget(self.run_button)
65 88 main_layout.addLayout(action_layout)
66 89
67 90 self.frame.setLayout(main_layout)
68 91 self.setWidget(self.frame)
69 92
70 self.visibilityChanged[bool].connect( self.update_magic_helper )
93 # connect all the relevant signals to handlers
94 self.visibilityChanged[bool].connect( self._update_magic_helper )
71 95 self.search_class.activated[int].connect(
72 96 self.class_selected
73 97 )
74 98 self.search_line.textChanged[str].connect(
75 99 self.search_changed
76 100 )
77 101 self.search_list.itemDoubleClicked[QtGui.QListWidgetItem].connect(
78 102 self.paste_requested
79 103 )
80 104 self.paste_button.clicked[bool].connect(
81 105 self.paste_requested
82 106 )
83 107 self.run_button.clicked[bool].connect(
84 108 self.run_requested
85 109 )
86 110
87 def update_magic_helper(self, visible):
111 #---------------------------------------------------------------------------
112 # implementation
113 #---------------------------------------------------------------------------
114
115 def _update_magic_helper(self, visible):
116 """Start update sequence.
117 This method is called when MagicHelper becomes visible. It clears
118 the content and emits readyForUpdate signal. The owner of the
119 instance is expected to invoke populate_magic_helper() when magic
120 info is available.
121 """
88 122 if not visible or self.data != None:
89 123 return
90 124 self.data = {}
91 125 self.search_class.clear()
92 126 self.search_class.addItem("Populating...")
127 self.search_list.clear()
93 128 self.readyForUpdate.emit()
94 129
95 130 def populate_magic_helper(self, data):
131 """Expects data returned by lsmagics query from kernel.
132 Populates the search_class and search_list with relevant items.
133 """
96 134 self.search_class.clear()
97 135 self.search_list.clear()
98 136
99 137 self.data = json.loads(
100 138 data['data'].get('application/json', {})
101 139 )
102 140
103 141 self.search_class.addItem('All Magics', 'any')
104 142 classes = set()
105 143
106 144 for mtype in sorted(self.data):
107 145 subdict = self.data[mtype]
108 146 for name in sorted(subdict):
109 147 classes.add(subdict[name])
110 148
111 149 for cls in sorted(classes):
112 150 label = re.sub("([a-zA-Z]+)([A-Z][a-z])","\g<1> \g<2>", cls)
113 151 self.search_class.addItem(label, cls)
114 152
115 153 self.filter_magic_helper('.', 'any')
116 154
117 155 def class_selected(self, index):
156 """Handle search_class selection changes
157 """
118 158 item = self.search_class.itemData(index)
119 159 regex = self.search_line.text()
120 160 self.filter_magic_helper(regex = regex, cls = item)
121 161
122 162 def search_changed(self, search_string):
163 """Handle search_line text changes.
164 The text is interpreted as a regular expression
165 """
123 166 item = self.search_class.itemData(
124 167 self.search_class.currentIndex()
125 168 )
126 169 self.filter_magic_helper(regex = search_string, cls = item)
127 170
128 171 def _get_current_search_item(self, item = None):
172 """Retrieve magic command currently selected in the search_list
173 """
129 174 text = None
130 175 if not isinstance(item, QtGui.QListWidgetItem):
131 176 item = self.search_list.currentItem()
132 177 text = item.text()
133 178 return text
134 179
135 180 def paste_requested(self, item = None):
181 """Emit pasteRequested signal with currently selected item text
182 """
136 183 text = self._get_current_search_item(item)
137 184 if text != None:
138 185 self.pasteRequested.emit(text)
139 186
140 187 def run_requested(self, item = None):
188 """Emit runRequested signal with currently selected item text
189 """
141 190 text = self._get_current_search_item(item)
142 191 if text != None:
143 192 self.runRequested.emit(text)
144 193
145 194 def filter_magic_helper(self, regex, cls):
195 """Update search_list with magic commands whose text match
196 regex and class match cls.
197 If cls equals 'any' - any class matches.
198 """
146 199 if regex == "" or regex == None:
147 200 regex = '.'
148 201 if cls == None:
149 202 cls = 'any'
150 203
151 204 self.search_list.clear()
152 205 for mtype in sorted(self.data):
153 206 subdict = self.data[mtype]
154 207 prefix = magic_escapes[mtype]
155 208
156 209 for name in sorted(subdict):
157 210 mclass = subdict[name]
158 211 pmagic = prefix + name
159 212
160 213 if (re.match(regex, name) or re.match(regex, pmagic)) and \
161 214 (cls == 'any' or cls == mclass):
162 215 self.search_list.addItem(pmagic)
163 216
General Comments 0
You need to be logged in to leave comments. Login now