Show More
@@ -407,7 +407,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
407 | if not self._hidden and not self._is_from_this_session(msg): |
|
407 | if not self._hidden and not self._is_from_this_session(msg): | |
408 | if self._local_kernel: |
|
408 | if self._local_kernel: | |
409 | if not msg['content']['restart']: |
|
409 | if not msg['content']['restart']: | |
410 |
s |
|
410 | self.exit_requested.emit(self) | |
411 | else: |
|
411 | else: | |
412 | # we just got notified of a restart! |
|
412 | # we just got notified of a restart! | |
413 | time.sleep(0.25) # wait 1/4 sec to reset |
|
413 | time.sleep(0.25) # wait 1/4 sec to reset |
@@ -87,30 +87,14 b' class MainWindow(QtGui.QMainWindow):' | |||||
87 |
|
87 | |||
88 | If may_close is True, then this Console is permitted to close the kernel |
|
88 | If may_close is True, then this Console is permitted to close the kernel | |
89 | """ |
|
89 | """ | |
90 | # ** current atributes, for window: |
|
|||
91 | # _existing, (kernel) passed by constructor. |
|
|||
92 | # _may_close (the kernel) passed by constructor |
|
|||
93 | # _confirm_exit |
|
|||
94 | # |
|
|||
95 | # ** for the frontend |
|
|||
96 | # _keep_kernel_on_exit (may be set by %exit) |
|
|||
97 |
|
90 | |||
98 | super(MainWindow, self).__init__() |
|
91 | super(MainWindow, self).__init__() | |
99 | self._app = app |
|
92 | self._app = app | |
100 | #self._frontend = frontend |
|
|||
101 | #self._existing = existing |
|
|||
102 | #if existing: |
|
|||
103 | # self._may_close = may_close |
|
|||
104 | #else: |
|
|||
105 | # self._may_close = True |
|
|||
106 | #self._frontend.exit_requested.connect(self.close) |
|
|||
107 | #self._confirm_exit = confirm_exit |
|
|||
108 |
|
93 | |||
109 | self.tabWidget = QtGui.QTabWidget(self) |
|
94 | self.tabWidget = QtGui.QTabWidget(self) | |
110 | self.tabWidget.setDocumentMode(True) |
|
95 | self.tabWidget.setDocumentMode(True) | |
111 | self.tabWidget.setTabsClosable(True) |
|
96 | self.tabWidget.setTabsClosable(True) | |
112 | #self.tabWidget.addTab(frontend,"QtConsole1") |
|
97 | self.tabWidget.tabCloseRequested[int].connect(self.closeTab) | |
113 | self.tabWidget.tabCloseRequested[int].connect(self.closetab) |
|
|||
114 |
|
98 | |||
115 | self.setCentralWidget(self.tabWidget) |
|
99 | self.setCentralWidget(self.tabWidget) | |
116 | self.updateTabBarVisibility() |
|
100 | self.updateTabBarVisibility() | |
@@ -118,8 +102,10 b' class MainWindow(QtGui.QMainWindow):' | |||||
118 | def updateTabBarVisibility(self): |
|
102 | def updateTabBarVisibility(self): | |
119 | """ update visibility of the tabBar depending of the number of tab |
|
103 | """ update visibility of the tabBar depending of the number of tab | |
120 |
|
104 | |||
121 |
0 or 1 tab, tabBar hidden |
|
105 | 0 or 1 tab, tabBar hidden | |
122 |
2+ tabs, tab |
|
106 | 2+ tabs, tabBar visible | |
|
107 | ||||
|
108 | send a self.close if number of tab ==0 | |||
123 |
|
109 | |||
124 | need to be called explicitely, or be connected to tabInserted/tabRemoved |
|
110 | need to be called explicitely, or be connected to tabInserted/tabRemoved | |
125 | """ |
|
111 | """ | |
@@ -127,23 +113,54 b' class MainWindow(QtGui.QMainWindow):' | |||||
127 | self.tabWidget.tabBar().setVisible(False) |
|
113 | self.tabWidget.tabBar().setVisible(False) | |
128 | else: |
|
114 | else: | |
129 | self.tabWidget.tabBar().setVisible(True) |
|
115 | self.tabWidget.tabBar().setVisible(True) | |
|
116 | if self.tabWidget.count()==0 : | |||
|
117 | self.close() | |||
130 |
|
118 | |||
131 | @property |
|
119 | @property | |
132 | def activeFrontend(self): |
|
120 | def activeFrontend(self): | |
133 | return self.tabWidget.currentWidget() |
|
121 | return self.tabWidget.currentWidget() | |
134 |
|
122 | |||
135 |
def close |
|
123 | def closeTab(self,currentTab): | |
136 |
""" Called when |
|
124 | """ Called when you need to try to close a tab. | |
137 |
|
125 | |||
138 |
It takes the number of the tab to be closed as argument, |
|
126 | It takes the number of the tab to be closed as argument, or a referece | |
139 | now, but should) take care of whether or not shuting down the kernel |
|
127 | to the wiget insite this tab | |
140 | attached to the frontend |
|
|||
141 | """ |
|
128 | """ | |
142 | print "trying to closing tab",tab |
|
129 | ||
143 | closing_widget=self.tabWidget.widget(tab) |
|
130 | # let's be sure "tab" and "closing widget are respectivey the index of the tab to close | |
|
131 | # and a reference to the trontend to close | |||
|
132 | if type(currentTab) is not int : | |||
|
133 | currentTab = self.tabWidget.indexOf(currentTab) | |||
|
134 | closing_widget=self.tabWidget.widget(currentTab) | |||
|
135 | ||||
|
136 | ||||
|
137 | # when trying to be closed, widget might re-send a request to be closed again, but will | |||
|
138 | # be deleted when event will be processed. So need to check that widget still exist and | |||
|
139 | # skip if not. One example of this is when 'exit' is send in a slave tab. 'exit' will be | |||
|
140 | # re-send by this fonction on the master widget, which ask all slaves widget to exit | |||
|
141 | if closing_widget==None: | |||
|
142 | return | |||
|
143 | ||||
|
144 | #get a list of all wwidget not owning the kernel. | |||
|
145 | slaveTabs=self.findSlavesTabs(closing_widget) | |||
|
146 | ||||
144 | keepkernel = None #Use the prompt by default |
|
147 | keepkernel = None #Use the prompt by default | |
145 | if hasattr(closing_widget,'_keep_kernel_on_exit'): #set by exit magic |
|
148 | if hasattr(closing_widget,'_keep_kernel_on_exit'): #set by exit magic | |
146 | keepkernel = closing_widget._keep_kernel_on_exit |
|
149 | keepkernel = closing_widget._keep_kernel_on_exit | |
|
150 | # If signal sent by exist magic (_keep_kernel_on_exit, exist and not None) | |||
|
151 | # we set local slave tabs._hidden to True to avoit prompting for kernel | |||
|
152 | # restart when they litt get the signal. and the "forward" the 'exit' | |||
|
153 | # to the main win | |||
|
154 | if keepkernel is not None: | |||
|
155 | for tab in slaveTabs: | |||
|
156 | tab._hidden = True | |||
|
157 | if closing_widget in slaveTabs : | |||
|
158 | try : | |||
|
159 | self.findMasterTab(closing_widget).pasteMagic('exit') | |||
|
160 | except AttributeError: | |||
|
161 | self.log.info("Master already closed or not local, closing only current tab") | |||
|
162 | self.tabWidget.removeTab(currentTab) | |||
|
163 | return | |||
147 |
|
164 | |||
148 | kernel_manager = closing_widget.kernel_manager |
|
165 | kernel_manager = closing_widget.kernel_manager | |
149 |
|
166 | |||
@@ -158,7 +175,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
158 | cancel = QtGui.QMessageBox.Cancel |
|
175 | cancel = QtGui.QMessageBox.Cancel | |
159 | okay = QtGui.QMessageBox.Ok |
|
176 | okay = QtGui.QMessageBox.Ok | |
160 | if closing_widget._may_close: |
|
177 | if closing_widget._may_close: | |
161 |
msg = "You are closing th |
|
178 | msg = "You are closing the tab : "+'"'+self.tabWidget.tabText(currentTab)+'"' | |
162 | info = "Would you like to quit the Kernel and all attached Consoles as well?" |
|
179 | info = "Would you like to quit the Kernel and all attached Consoles as well?" | |
163 | justthis = QtGui.QPushButton("&No, just this Console", self) |
|
180 | justthis = QtGui.QPushButton("&No, just this Console", self) | |
164 | justthis.setShortcut('N') |
|
181 | justthis.setShortcut('N') | |
@@ -177,19 +194,14 b' class MainWindow(QtGui.QMainWindow):' | |||||
177 | box.setIconPixmap(scaledpixmap) |
|
194 | box.setIconPixmap(scaledpixmap) | |
178 | reply = box.exec_() |
|
195 | reply = box.exec_() | |
179 | if reply == 1: # close All |
|
196 | if reply == 1: # close All | |
180 | kernel_manager.shutdown_kernel() |
|
197 | for slave in slaveTabs: | |
|
198 | self.tabWidget.removeTab(self.tabWidget.indexOf(slave)) | |||
181 | closing_widget.pasteMagic("exit") |
|
199 | closing_widget.pasteMagic("exit") | |
182 | self.tabWidget.removeTab(tab) |
|
200 | self.tabWidget.removeTab(currentTab) | |
183 | #kernel_manager.stop_channels() |
|
|||
184 | #event.accept() |
|
|||
185 | elif reply == 0: # close Console |
|
201 | elif reply == 0: # close Console | |
186 | if not closing_widget._existing: |
|
202 | if not closing_widget._existing: | |
187 | # Have kernel: don't quit, just close the window |
|
203 | # Have kernel: don't quit, just close the window | |
188 | self._app.setQuitOnLastWindowClosed(False) |
|
204 | closing_widget.pasteMagic("exit True") | |
189 | self.deleteLater() |
|
|||
190 | #event.accept() |
|
|||
191 | #else: |
|
|||
192 | #event.ignore() |
|
|||
193 | else: |
|
205 | else: | |
194 | reply = QtGui.QMessageBox.question(self, title, |
|
206 | reply = QtGui.QMessageBox.question(self, title, | |
195 | "Are you sure you want to close this Console?"+ |
|
207 | "Are you sure you want to close this Console?"+ | |
@@ -198,29 +210,20 b' class MainWindow(QtGui.QMainWindow):' | |||||
198 | defaultButton=okay |
|
210 | defaultButton=okay | |
199 | ) |
|
211 | ) | |
200 | if reply == okay: |
|
212 | if reply == okay: | |
201 | self.tabWidget.removeTab(tab) |
|
213 | self.tabWidget.removeTab(currentTab) | |
202 | else: |
|
214 | else: | |
203 | event.ignore() |
|
215 | event.ignore() | |
204 | elif keepkernel: #close console but leave kernel running (no prompt) |
|
216 | elif keepkernel: #close console but leave kernel running (no prompt) | |
205 | if kernel_manager and kernel_manager.channels_running: |
|
217 | if kernel_manager and kernel_manager.channels_running: | |
206 |
if not c |
|
218 | if not closing_widget._existing: | |
207 | # I have the kernel: don't quit, just close the window |
|
219 | # I have the kernel: don't quit, just close the window | |
208 | self._app.setQuitOnLastWindowClosed(False) |
|
220 | self.tabWidget.removeTab(currentTab) | |
209 | #event.accept() |
|
|||
210 | else: #close console and kernel (no prompt) |
|
221 | else: #close console and kernel (no prompt) | |
211 | if kernel_manager and kernel_manager.channels_running: |
|
222 | if kernel_manager and kernel_manager.channels_running: | |
|
223 | for slave in slaveTabs: | |||
|
224 | self.tabWidget.removeTab(self.tabWidget.indexOf(slave)) | |||
|
225 | self.tabWidget.removeTab(currentTab) | |||
212 | kernel_manager.shutdown_kernel() |
|
226 | kernel_manager.shutdown_kernel() | |
213 | #event.accept() |
|
|||
214 | #try: |
|
|||
215 | # if closing_widget._local_kernel and not keepkernel: |
|
|||
216 | # kernel_manager = self.tabWidget.widget(tab).kernel_manager.shutdown_kernel() |
|
|||
217 | # else: |
|
|||
218 | # print "not owning the kernel/asked not to shut it down" |
|
|||
219 | #except: |
|
|||
220 | # print "can't ask the kernel to shutdown" |
|
|||
221 | #if self.tabWidget.count() == 1: |
|
|||
222 | #self.close() |
|
|||
223 | #self.tabWidget.removeTab(tab) |
|
|||
224 | self.updateTabBarVisibility() |
|
227 | self.updateTabBarVisibility() | |
225 |
|
228 | |||
226 | def addTabWithFrontend(self,frontend,name=None): |
|
229 | def addTabWithFrontend(self,frontend,name=None): | |
@@ -231,16 +234,84 b' class MainWindow(QtGui.QMainWindow):' | |||||
231 | name=str('no Name '+str(self.tabWidget.count())) |
|
234 | name=str('no Name '+str(self.tabWidget.count())) | |
232 | self.tabWidget.addTab(frontend,name) |
|
235 | self.tabWidget.addTab(frontend,name) | |
233 | self.updateTabBarVisibility() |
|
236 | self.updateTabBarVisibility() | |
234 |
frontend.exit_requested.connect(self. |
|
237 | frontend.exit_requested.connect(self.closeTab) | |
|
238 | ||||
|
239 | def findMasterTab(self,tab,asList=False): | |||
|
240 | """ | |||
|
241 | Try to return the frontend that own the kernel attached to the given widget/tab. | |||
|
242 | ||||
|
243 | Only find frontend owed by the current application. Selection | |||
|
244 | based on port of the kernel, might be inacurate if several kernel | |||
|
245 | on different ip use same port number. | |||
|
246 | ||||
|
247 | This fonction does the conversion tabNumber/widget if needed. | |||
|
248 | Might return None if no master widget (non local kernel) | |||
|
249 | Will crash IPython if more than 1 masterWidget | |||
|
250 | ||||
|
251 | When asList set to True, always return a list of widget(s) owning | |||
|
252 | the kernel. The list might be empty or containing several Widget. | |||
|
253 | """ | |||
|
254 | ||||
|
255 | #convert from/to int/richIpythonWidget if needed | |||
|
256 | if type(tab) == int: | |||
|
257 | tab = self.tabWidget.widget(tab) | |||
|
258 | km=tab.kernel_manager; | |||
|
259 | ||||
|
260 | #build list of all widgets | |||
|
261 | widgetList = [self.tabWidget.widget(i) for i in range(self.tabWidget.count())] | |||
|
262 | ||||
|
263 | # widget that are candidate to be the owner of the kernel does have all the same port of the curent widget | |||
|
264 | # And should have a _may_close attribute | |||
|
265 | filtredwidgetList = [ widget for widget in widgetList if | |||
|
266 | widget.kernel_manager.shell_address == km.shell_address and | |||
|
267 | widget.kernel_manager.sub_address == km.sub_address and | |||
|
268 | widget.kernel_manager.stdin_address == km.stdin_address and | |||
|
269 | widget.kernel_manager.hb_address == km.hb_address and | |||
|
270 | hasattr(widget,'_may_close') ] | |||
|
271 | # the master widget is the one that may close the kernel | |||
|
272 | masterWidget= [ widget for widget in filtredwidgetList if widget._may_close] | |||
|
273 | if asList: | |||
|
274 | return masterWidget | |||
|
275 | assert(len(masterWidget)<=1 ) | |||
|
276 | if len(masterWidget)==0: | |||
|
277 | return None | |||
|
278 | ||||
|
279 | return masterWidget[0] | |||
|
280 | ||||
|
281 | def findSlavesTabs(self,tab): | |||
|
282 | """ | |||
|
283 | Try to return all the frontend that do not own the kernel attached to the given widget/tab. | |||
|
284 | ||||
|
285 | Only find frontend owed by the current application. Selection | |||
|
286 | based on port of the kernel, might be innacurate if several kernel | |||
|
287 | on different ip use same port number. | |||
|
288 | ||||
|
289 | This fonction does the conversion tabNumber/widget if needed. | |||
|
290 | """ | |||
|
291 | #convert from/to int/richIpythonWidget if needed | |||
|
292 | if type(tab) == int: | |||
|
293 | tab = self.tabWidget.widget(tab) | |||
|
294 | km=tab.kernel_manager; | |||
|
295 | ||||
|
296 | #build list of all widgets | |||
|
297 | widgetList = [self.tabWidget.widget(i) for i in range(self.tabWidget.count())] | |||
|
298 | ||||
|
299 | # widget that are candidate not to be the owner of the kernel does have all the same port of the curent widget | |||
|
300 | filtredWidgetList = ( widget for widget in widgetList if | |||
|
301 | widget.kernel_manager.shell_address == km.shell_address and | |||
|
302 | widget.kernel_manager.sub_address == km.sub_address and | |||
|
303 | widget.kernel_manager.stdin_address == km.stdin_address and | |||
|
304 | widget.kernel_manager.hb_address == km.hb_address) | |||
|
305 | # Get a list of all widget owning the same kernel and removed it from | |||
|
306 | # the previous cadidate. (better using sets ?) | |||
|
307 | masterWidgetlist = self.findMasterTab(tab,asList=True) | |||
|
308 | slaveList = [widget for widget in filtredWidgetList if widget not in masterWidgetlist] | |||
|
309 | ||||
|
310 | return slaveList | |||
235 |
|
311 | |||
236 | def irequest(self,obj): |
|
|||
237 | print "I request to exit",obj |
|
|||
238 | print "which is tab:",self.tabWidget.indexOf(obj) |
|
|||
239 | self.closetab(self.tabWidget.indexOf(obj)) |
|
|||
240 | # MenuBar is always present on Mac Os, so let's populate it with possible |
|
312 | # MenuBar is always present on Mac Os, so let's populate it with possible | |
241 | # action, don't do it on other platform as some user might not want the |
|
313 | # action, don't do it on other platform as some user might not want the | |
242 | # menu bar, or give them an option to remove it |
|
314 | # menu bar, or give them an option to remove it | |
243 |
|
||||
244 | def initMenuBar(self): |
|
315 | def initMenuBar(self): | |
245 | #create menu in the order they should appear in the menu bar |
|
316 | #create menu in the order they should appear in the menu bar | |
246 | self.fileMenu = self.menuBar().addMenu("File") |
|
317 | self.fileMenu = self.menuBar().addMenu("File") | |
@@ -267,7 +338,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
267 | triggered=self.print_action_active_frontend) |
|
338 | triggered=self.print_action_active_frontend) | |
268 | self.fileMenu.addAction(self.print_action) |
|
339 | self.fileMenu.addAction(self.print_action) | |
269 | except AttributeError: |
|
340 | except AttributeError: | |
270 |
|
|
341 | self.log.error("trying to add unexisting action (print), skipping") | |
271 |
|
342 | |||
272 | try: |
|
343 | try: | |
273 | self.export_action=QtGui.QAction("Export", |
|
344 | self.export_action=QtGui.QAction("Export", | |
@@ -277,7 +348,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
277 | ) |
|
348 | ) | |
278 | self.fileMenu.addAction(self.export_action) |
|
349 | self.fileMenu.addAction(self.export_action) | |
279 | except AttributeError: |
|
350 | except AttributeError: | |
280 |
|
|
351 | self.log.error("trying to add unexisting action (Export), skipping") | |
281 |
|
352 | |||
282 | try: |
|
353 | try: | |
283 | self.select_all_action = QtGui.QAction("Select All", |
|
354 | self.select_all_action = QtGui.QAction("Select All", | |
@@ -287,7 +358,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
287 | ) |
|
358 | ) | |
288 | self.fileMenu.addAction(self.select_all_action) |
|
359 | self.fileMenu.addAction(self.select_all_action) | |
289 | except AttributeError: |
|
360 | except AttributeError: | |
290 |
|
|
361 | self.log.error("trying to add unexisting action (select all), skipping") | |
291 |
|
362 | |||
292 | try: |
|
363 | try: | |
293 | self.undo_action = QtGui.QAction("Undo", |
|
364 | self.undo_action = QtGui.QAction("Undo", | |
@@ -298,7 +369,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
298 | ) |
|
369 | ) | |
299 | self.editMenu.addAction(self.undo_action) |
|
370 | self.editMenu.addAction(self.undo_action) | |
300 | except AttributeError: |
|
371 | except AttributeError: | |
301 |
|
|
372 | self.log.error("trying to add unexisting action (undo), skipping") | |
302 |
|
373 | |||
303 | try: |
|
374 | try: | |
304 | self.redo_action = QtGui.QAction("Redo", |
|
375 | self.redo_action = QtGui.QAction("Redo", | |
@@ -308,7 +379,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
308 | triggered=self.redo_active_frontend) |
|
379 | triggered=self.redo_active_frontend) | |
309 | self.editMenu.addAction(self.redo_action) |
|
380 | self.editMenu.addAction(self.redo_action) | |
310 | except AttributeError: |
|
381 | except AttributeError: | |
311 |
|
|
382 | self.log.error("trying to add unexisting action (redo), skipping") | |
312 |
|
383 | |||
313 | try: |
|
384 | try: | |
314 | self.increase_font_size = QtGui.QAction("Increase Font Size", |
|
385 | self.increase_font_size = QtGui.QAction("Increase Font Size", | |
@@ -318,7 +389,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
318 | ) |
|
389 | ) | |
319 | self.fontMenu.addAction(self.increase_font_size) |
|
390 | self.fontMenu.addAction(self.increase_font_size) | |
320 | except AttributeError: |
|
391 | except AttributeError: | |
321 |
|
|
392 | self.log.error("trying to add unexisting action (increase font size), skipping") | |
322 |
|
393 | |||
323 | try: |
|
394 | try: | |
324 | self.decrease_font_size = QtGui.QAction("Decrease Font Size", |
|
395 | self.decrease_font_size = QtGui.QAction("Decrease Font Size", | |
@@ -328,7 +399,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
328 | ) |
|
399 | ) | |
329 | self.fontMenu.addAction(self.decrease_font_size) |
|
400 | self.fontMenu.addAction(self.decrease_font_size) | |
330 | except AttributeError: |
|
401 | except AttributeError: | |
331 |
|
|
402 | self.log.error("trying to add unexisting action (decrease font size), skipping") | |
332 |
|
403 | |||
333 | try: |
|
404 | try: | |
334 | self.reset_font_size = QtGui.QAction("Reset Font Size", |
|
405 | self.reset_font_size = QtGui.QAction("Reset Font Size", | |
@@ -338,7 +409,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
338 | ) |
|
409 | ) | |
339 | self.fontMenu.addAction(self.reset_font_size) |
|
410 | self.fontMenu.addAction(self.reset_font_size) | |
340 | except AttributeError: |
|
411 | except AttributeError: | |
341 |
|
|
412 | self.log.error("trying to add unexisting action (reset font size), skipping") | |
342 |
|
413 | |||
343 | try: |
|
414 | try: | |
344 | self.reset_action = QtGui.QAction("Reset", |
|
415 | self.reset_action = QtGui.QAction("Reset", | |
@@ -347,7 +418,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
347 | triggered=self.reset_magic_active_frontend) |
|
418 | triggered=self.reset_magic_active_frontend) | |
348 | self.magicMenu.addAction(self.reset_action) |
|
419 | self.magicMenu.addAction(self.reset_action) | |
349 | except AttributeError: |
|
420 | except AttributeError: | |
350 |
|
|
421 | self.log.error("trying to add unexisting action (reset), skipping") | |
351 |
|
422 | |||
352 | try: |
|
423 | try: | |
353 | self.history_action = QtGui.QAction("History", |
|
424 | self.history_action = QtGui.QAction("History", | |
@@ -356,7 +427,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
356 | triggered=self.history_magic_active_frontend) |
|
427 | triggered=self.history_magic_active_frontend) | |
357 | self.magicMenu.addAction(self.history_action) |
|
428 | self.magicMenu.addAction(self.history_action) | |
358 | except AttributeError: |
|
429 | except AttributeError: | |
359 |
|
|
430 | self.log.error("trying to add unexisting action (history), skipping") | |
360 |
|
431 | |||
361 | try: |
|
432 | try: | |
362 | self.save_action = QtGui.QAction("Export History ", |
|
433 | self.save_action = QtGui.QAction("Export History ", | |
@@ -365,7 +436,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
365 | triggered=self.save_magic_active_frontend) |
|
436 | triggered=self.save_magic_active_frontend) | |
366 | self.magicMenu.addAction(self.save_action) |
|
437 | self.magicMenu.addAction(self.save_action) | |
367 | except AttributeError: |
|
438 | except AttributeError: | |
368 |
|
|
439 | self.log.error("trying to add unexisting action (save), skipping") | |
369 |
|
440 | |||
370 | try: |
|
441 | try: | |
371 | self.clear_action = QtGui.QAction("Clear", |
|
442 | self.clear_action = QtGui.QAction("Clear", | |
@@ -374,7 +445,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
374 | triggered=self.clear_magic_active_frontend) |
|
445 | triggered=self.clear_magic_active_frontend) | |
375 | self.magicMenu.addAction(self.clear_action) |
|
446 | self.magicMenu.addAction(self.clear_action) | |
376 | except AttributeError: |
|
447 | except AttributeError: | |
377 |
|
|
448 | self.log.error("trying to add unexisting action, skipping") | |
378 |
|
449 | |||
379 | try: |
|
450 | try: | |
380 | self.who_action = QtGui.QAction("Who", |
|
451 | self.who_action = QtGui.QAction("Who", | |
@@ -383,7 +454,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
383 | triggered=self.who_magic_active_frontend) |
|
454 | triggered=self.who_magic_active_frontend) | |
384 | self.magicMenu.addAction(self.who_action) |
|
455 | self.magicMenu.addAction(self.who_action) | |
385 | except AttributeError: |
|
456 | except AttributeError: | |
386 |
|
|
457 | self.log.error("trying to add unexisting action (who), skipping") | |
387 |
|
458 | |||
388 | try: |
|
459 | try: | |
389 | self.who_ls_action = QtGui.QAction("Who ls", |
|
460 | self.who_ls_action = QtGui.QAction("Who ls", | |
@@ -392,7 +463,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
392 | triggered=self.who_ls_magic_active_frontend) |
|
463 | triggered=self.who_ls_magic_active_frontend) | |
393 | self.magicMenu.addAction(self.who_ls_action) |
|
464 | self.magicMenu.addAction(self.who_ls_action) | |
394 | except AttributeError: |
|
465 | except AttributeError: | |
395 |
|
|
466 | self.log.error("trying to add unexisting action (who_ls), skipping") | |
396 |
|
467 | |||
397 | try: |
|
468 | try: | |
398 | self.whos_action = QtGui.QAction("Whos", |
|
469 | self.whos_action = QtGui.QAction("Whos", | |
@@ -401,7 +472,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
401 | triggered=self.whos_magic_active_frontend) |
|
472 | triggered=self.whos_magic_active_frontend) | |
402 | self.magicMenu.addAction(self.whos_action) |
|
473 | self.magicMenu.addAction(self.whos_action) | |
403 | except AttributeError: |
|
474 | except AttributeError: | |
404 |
|
|
475 | self.log.error("trying to add unexisting action (whos), skipping") | |
405 |
|
476 | |||
406 | def undo_active_frontend(self): |
|
477 | def undo_active_frontend(self): | |
407 | self.activeFrontend.undo() |
|
478 | self.activeFrontend.undo() | |
@@ -441,103 +512,15 b' class MainWindow(QtGui.QMainWindow):' | |||||
441 | #--------------------------------------------------------------------------- |
|
512 | #--------------------------------------------------------------------------- | |
442 | # QWidget interface |
|
513 | # QWidget interface | |
443 | #--------------------------------------------------------------------------- |
|
514 | #--------------------------------------------------------------------------- | |
444 |
|
515 | |||
445 | def closeEvent(self, event): |
|
516 | def closeEvent(self, event): | |
446 | """ Close the window and the kernel (if necessary). |
|
517 | """ Forward the close event to every tabs contained by the windows | |
447 |
|
||||
448 | This will prompt the user if they are finished with the kernel, and if |
|
|||
449 | so, closes the kernel cleanly. Alternatively, if the exit magic is used, |
|
|||
450 | it closes without prompt. |
|
|||
451 | """ |
|
518 | """ | |
452 | # Should change the logic |
|
519 | # Do Not loop on the widget count as it change while closing | |
453 | # put this code iin a per tab bases, with each atributes specified on the tab. |
|
520 | widgetList=[ self.tabWidget.widget(i) for i in range(self.tabWidget.count())] | |
454 | # otherwise, we should ask the user: |
|
521 | for widget in widgetList: | |
455 | # ==================================== |
|
522 | self.closeTab(widget) | |
456 | # close all the tabs and kernel ? |
|
523 | event.accept() | |
457 | # Yes | No | Cancel | Keep the kernel runing | Ask for each |
|
|||
458 | # ==================================== |
|
|||
459 | # We might also add an action "close all `non local kernel` console" |
|
|||
460 |
|
||||
461 |
|
||||
462 | # Closing widget is based on the tab index, so we have to build the |
|
|||
463 | # list of widget before actually looping throught it. By Sending the %exit magic |
|
|||
464 | # you are sure to avoid question about restarting the kernel. Otherwise you'll have to |
|
|||
465 | # close the 'non local kernel' tabs before |
|
|||
466 |
|
||||
467 | #allWidget = [ self.tabWidget.widget(n) for n in range(self.tabWidget.count())] |
|
|||
468 |
|
||||
469 | #for w in allWidget: |
|
|||
470 | # w.exit_magic() |
|
|||
471 | #return |
|
|||
472 |
|
||||
473 | #keepkernel = None #Use the prompt by default |
|
|||
474 | #if hasattr(self._frontend,'_keep_kernel_on_exit'): #set by exit magic |
|
|||
475 | # keepkernel = self._frontend._keep_kernel_on_exit |
|
|||
476 |
|
||||
477 | #kernel_manager = self._frontend.kernel_manager |
|
|||
478 |
|
||||
479 | #if keepkernel is None and not self._confirm_exit: |
|
|||
480 | # # don't prompt, just terminate the kernel if we own it |
|
|||
481 | # # or leave it alone if we don't |
|
|||
482 | # keepkernel = not self._existing |
|
|||
483 | return |
|
|||
484 | if keepkernel is None: #show prompt |
|
|||
485 | if kernel_manager and kernel_manager.channels_running: |
|
|||
486 | title = self.window().windowTitle() |
|
|||
487 | cancel = QtGui.QMessageBox.Cancel |
|
|||
488 | okay = QtGui.QMessageBox.Ok |
|
|||
489 | if self._may_close: |
|
|||
490 | msg = "You are closing this Console window." |
|
|||
491 | info = "Would you like to quit the Kernel and all attached Consoles as well?" |
|
|||
492 | justthis = QtGui.QPushButton("&No, just this Console", self) |
|
|||
493 | justthis.setShortcut('N') |
|
|||
494 | closeall = QtGui.QPushButton("&Yes, quit everything", self) |
|
|||
495 | closeall.setShortcut('Y') |
|
|||
496 | box = QtGui.QMessageBox(QtGui.QMessageBox.Question, |
|
|||
497 | title, msg) |
|
|||
498 | box.setInformativeText(info) |
|
|||
499 | box.addButton(cancel) |
|
|||
500 | box.addButton(justthis, QtGui.QMessageBox.NoRole) |
|
|||
501 | box.addButton(closeall, QtGui.QMessageBox.YesRole) |
|
|||
502 | box.setDefaultButton(closeall) |
|
|||
503 | box.setEscapeButton(cancel) |
|
|||
504 | pixmap = QtGui.QPixmap(':/icon/IPythonConsole.png') |
|
|||
505 | scaledpixmap = pixmap.scaledToWidth(64,mode=QtCore.Qt.SmoothTransformation) |
|
|||
506 | box.setIconPixmap(scaledpixmap) |
|
|||
507 | reply = box.exec_() |
|
|||
508 | if reply == 1: # close All |
|
|||
509 | kernel_manager.shutdown_kernel() |
|
|||
510 | #kernel_manager.stop_channels() |
|
|||
511 | event.accept() |
|
|||
512 | elif reply == 0: # close Console |
|
|||
513 | if not self._existing: |
|
|||
514 | # Have kernel: don't quit, just close the window |
|
|||
515 | self._app.setQuitOnLastWindowClosed(False) |
|
|||
516 | self.deleteLater() |
|
|||
517 | event.accept() |
|
|||
518 | else: |
|
|||
519 | event.ignore() |
|
|||
520 | else: |
|
|||
521 | reply = QtGui.QMessageBox.question(self, title, |
|
|||
522 | "Are you sure you want to close this Console?"+ |
|
|||
523 | "\nThe Kernel and other Consoles will remain active.", |
|
|||
524 | okay|cancel, |
|
|||
525 | defaultButton=okay |
|
|||
526 | ) |
|
|||
527 | if reply == okay: |
|
|||
528 | event.accept() |
|
|||
529 | else: |
|
|||
530 | event.ignore() |
|
|||
531 | elif keepkernel: #close console but leave kernel running (no prompt) |
|
|||
532 | if kernel_manager and kernel_manager.channels_running: |
|
|||
533 | if not self._existing: |
|
|||
534 | # I have the kernel: don't quit, just close the window |
|
|||
535 | self._app.setQuitOnLastWindowClosed(False) |
|
|||
536 | event.accept() |
|
|||
537 | else: #close console and kernel (no prompt) |
|
|||
538 | if kernel_manager and kernel_manager.channels_running: |
|
|||
539 | kernel_manager.shutdown_kernel() |
|
|||
540 | event.accept() |
|
|||
541 |
|
524 | |||
542 | #----------------------------------------------------------------------------- |
|
525 | #----------------------------------------------------------------------------- | |
543 | # Aliases and Flags |
|
526 | # Aliases and Flags | |
@@ -857,6 +840,7 b' class IPythonQtConsoleApp(BaseIPythonApplication):' | |||||
857 | widget = self.widget_factory(config=self.config, |
|
840 | widget = self.widget_factory(config=self.config, | |
858 | local_kernel=local_kernel) |
|
841 | local_kernel=local_kernel) | |
859 | widget.kernel_manager = kernel_manager |
|
842 | widget.kernel_manager = kernel_manager | |
|
843 | widget._existing=False; | |||
860 | widget._confirm_exit=True; |
|
844 | widget._confirm_exit=True; | |
861 | widget._may_close=True; |
|
845 | widget._may_close=True; | |
862 | self.window.addTabWithFrontend(widget) |
|
846 | self.window.addTabWithFrontend(widget) | |
@@ -892,10 +876,15 b' class IPythonQtConsoleApp(BaseIPythonApplication):' | |||||
892 | local_kernel = (not self.existing) or self.ip in LOCAL_IPS |
|
876 | local_kernel = (not self.existing) or self.ip in LOCAL_IPS | |
893 | self.widget = self.widget_factory(config=self.config, |
|
877 | self.widget = self.widget_factory(config=self.config, | |
894 | local_kernel=local_kernel) |
|
878 | local_kernel=local_kernel) | |
|
879 | self.widget._existing = self.existing; | |||
|
880 | self.widget._may_close = not self.existing; | |||
|
881 | self.widget._confirm_exit = not self.existing; | |||
|
882 | ||||
895 | self.widget.kernel_manager = self.kernel_manager |
|
883 | self.widget.kernel_manager = self.kernel_manager | |
896 | self.window = MainWindow(self.app, self.widget, self.existing, |
|
884 | self.window = MainWindow(self.app, self.widget, self.existing, | |
897 | may_close=local_kernel, |
|
885 | may_close=local_kernel, | |
898 | confirm_exit=self.confirm_exit) |
|
886 | confirm_exit=self.confirm_exit) | |
|
887 | self.window.log = self.log | |||
899 | self.window.addTabWithFrontend(self.widget) |
|
888 | self.window.addTabWithFrontend(self.widget) | |
900 | self.window.initMenuBar() |
|
889 | self.window.initMenuBar() | |
901 | self.window.setWindowTitle('Python' if self.pure else 'IPython') |
|
890 | self.window.setWindowTitle('Python' if self.pure else 'IPython') |
General Comments 0
You need to be logged in to leave comments.
Login now