##// END OF EJS Templates
fix inverted OSX platform check
MinRK -
Show More
@@ -1,806 +1,806 b''
1 1 """The Qt MainWindow for the QtConsole
2 2
3 3 This is a tabbed pseudo-terminal of IPython sessions, with a menu bar for
4 4 common actions.
5 5
6 6 Authors:
7 7
8 8 * Evan Patterson
9 9 * Min RK
10 10 * Erik Tollerud
11 11 * Fernando Perez
12 12 * Bussonnier Matthias
13 13 * Thomas Kluyver
14 14
15 15 """
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Imports
19 19 #-----------------------------------------------------------------------------
20 20
21 21 # stdlib imports
22 22 import sys
23 23 import webbrowser
24 24
25 25 # System library imports
26 26 from IPython.external.qt import QtGui,QtCore
27 27
28 28 #-----------------------------------------------------------------------------
29 29 # Classes
30 30 #-----------------------------------------------------------------------------
31 31
32 32 class MainWindow(QtGui.QMainWindow):
33 33
34 34 #---------------------------------------------------------------------------
35 35 # 'object' interface
36 36 #---------------------------------------------------------------------------
37 37
38 38 def __init__(self, app,
39 39 confirm_exit=True,
40 40 new_frontend_factory=None, slave_frontend_factory=None,
41 41 ):
42 42 """ Create a tabbed MainWindow for managing IPython FrontendWidgets
43 43
44 44 Parameters
45 45 ----------
46 46
47 47 app : reference to QApplication parent
48 48 confirm_exit : bool, optional
49 49 Whether we should prompt on close of tabs
50 50 new_frontend_factory : callable
51 51 A callable that returns a new IPythonWidget instance, attached to
52 52 its own running kernel.
53 53 slave_frontend_factory : callable
54 54 A callable that takes an existing IPythonWidget, and returns a new
55 55 IPythonWidget instance, attached to the same kernel.
56 56 """
57 57
58 58 super(MainWindow, self).__init__()
59 59 self._app = app
60 60 self.confirm_exit = confirm_exit
61 61 self.new_frontend_factory = new_frontend_factory
62 62 self.slave_frontend_factory = slave_frontend_factory
63 63
64 64 self.tab_widget = QtGui.QTabWidget(self)
65 65 self.tab_widget.setDocumentMode(True)
66 66 self.tab_widget.setTabsClosable(True)
67 67 self.tab_widget.tabCloseRequested[int].connect(self.close_tab)
68 68
69 69 self.setCentralWidget(self.tab_widget)
70 70 self.tab_widget.tabBar().setVisible(False)
71 71
72 72 def update_tab_bar_visibility(self):
73 73 """ update visibility of the tabBar depending of the number of tab
74 74
75 75 0 or 1 tab, tabBar hidden
76 76 2+ tabs, tabBar visible
77 77
78 78 send a self.close if number of tab ==0
79 79
80 80 need to be called explicitely, or be connected to tabInserted/tabRemoved
81 81 """
82 82 if self.tab_widget.count() <= 1:
83 83 self.tab_widget.tabBar().setVisible(False)
84 84 else:
85 85 self.tab_widget.tabBar().setVisible(True)
86 86 if self.tab_widget.count()==0 :
87 87 self.close()
88 88
89 89 @property
90 90 def active_frontend(self):
91 91 return self.tab_widget.currentWidget()
92 92
93 93 def create_tab_with_new_frontend(self):
94 94 """create a new frontend and attach it to a new tab"""
95 95 widget = self.new_frontend_factory()
96 96 self.add_tab_with_frontend(widget)
97 97
98 98 def create_tab_with_current_kernel(self):
99 99 """create a new frontend attached to the same kernel as the current tab"""
100 100 current_widget = self.tab_widget.currentWidget()
101 101 current_widget_index = self.tab_widget.indexOf(current_widget)
102 102 current_widget_name = self.tab_widget.tabText(current_widget_index)
103 103 widget = self.slave_frontend_factory(current_widget)
104 104 if 'slave' in current_widget_name:
105 105 # don't keep stacking slaves
106 106 name = current_widget_name
107 107 else:
108 108 name = str('('+current_widget_name+') slave')
109 109 self.add_tab_with_frontend(widget,name=name)
110 110
111 111 def close_tab(self,current_tab):
112 112 """ Called when you need to try to close a tab.
113 113
114 114 It takes the number of the tab to be closed as argument, or a referece
115 115 to the wiget insite this tab
116 116 """
117 117
118 118 # let's be sure "tab" and "closing widget are respectivey the index of the tab to close
119 119 # and a reference to the trontend to close
120 120 if type(current_tab) is not int :
121 121 current_tab = self.tab_widget.indexOf(current_tab)
122 122 closing_widget=self.tab_widget.widget(current_tab)
123 123
124 124
125 125 # when trying to be closed, widget might re-send a request to be closed again, but will
126 126 # be deleted when event will be processed. So need to check that widget still exist and
127 127 # skip if not. One example of this is when 'exit' is send in a slave tab. 'exit' will be
128 128 # re-send by this fonction on the master widget, which ask all slaves widget to exit
129 129 if closing_widget==None:
130 130 return
131 131
132 132 #get a list of all slave widgets on the same kernel.
133 133 slave_tabs = self.find_slave_widgets(closing_widget)
134 134
135 135 keepkernel = None #Use the prompt by default
136 136 if hasattr(closing_widget,'_keep_kernel_on_exit'): #set by exit magic
137 137 keepkernel = closing_widget._keep_kernel_on_exit
138 138 # If signal sent by exit magic (_keep_kernel_on_exit, exist and not None)
139 139 # we set local slave tabs._hidden to True to avoid prompting for kernel
140 140 # restart when they get the signal. and then "forward" the 'exit'
141 141 # to the main window
142 142 if keepkernel is not None:
143 143 for tab in slave_tabs:
144 144 tab._hidden = True
145 145 if closing_widget in slave_tabs:
146 146 try :
147 147 self.find_master_tab(closing_widget).execute('exit')
148 148 except AttributeError:
149 149 self.log.info("Master already closed or not local, closing only current tab")
150 150 self.tab_widget.removeTab(current_tab)
151 151 self.update_tab_bar_visibility()
152 152 return
153 153
154 154 kernel_manager = closing_widget.kernel_manager
155 155
156 156 if keepkernel is None and not closing_widget._confirm_exit:
157 157 # don't prompt, just terminate the kernel if we own it
158 158 # or leave it alone if we don't
159 159 keepkernel = closing_widget._existing
160 160 if keepkernel is None: #show prompt
161 161 if kernel_manager and kernel_manager.channels_running:
162 162 title = self.window().windowTitle()
163 163 cancel = QtGui.QMessageBox.Cancel
164 164 okay = QtGui.QMessageBox.Ok
165 165 if closing_widget._may_close:
166 166 msg = "You are closing the tab : "+'"'+self.tab_widget.tabText(current_tab)+'"'
167 167 info = "Would you like to quit the Kernel and close all attached Consoles as well?"
168 168 justthis = QtGui.QPushButton("&No, just this Tab", self)
169 169 justthis.setShortcut('N')
170 170 closeall = QtGui.QPushButton("&Yes, close all", self)
171 171 closeall.setShortcut('Y')
172 172 box = QtGui.QMessageBox(QtGui.QMessageBox.Question,
173 173 title, msg)
174 174 box.setInformativeText(info)
175 175 box.addButton(cancel)
176 176 box.addButton(justthis, QtGui.QMessageBox.NoRole)
177 177 box.addButton(closeall, QtGui.QMessageBox.YesRole)
178 178 box.setDefaultButton(closeall)
179 179 box.setEscapeButton(cancel)
180 180 pixmap = QtGui.QPixmap(self._app.icon.pixmap(QtCore.QSize(64,64)))
181 181 box.setIconPixmap(pixmap)
182 182 reply = box.exec_()
183 183 if reply == 1: # close All
184 184 for slave in slave_tabs:
185 185 self.tab_widget.removeTab(self.tab_widget.indexOf(slave))
186 186 closing_widget.execute("exit")
187 187 self.tab_widget.removeTab(current_tab)
188 188 elif reply == 0: # close Console
189 189 if not closing_widget._existing:
190 190 # Have kernel: don't quit, just close the tab
191 191 closing_widget.execute("exit True")
192 192 self.tab_widget.removeTab(current_tab)
193 193 else:
194 194 reply = QtGui.QMessageBox.question(self, title,
195 195 "Are you sure you want to close this Console?"+
196 196 "\nThe Kernel and other Consoles will remain active.",
197 197 okay|cancel,
198 198 defaultButton=okay
199 199 )
200 200 if reply == okay:
201 201 self.tab_widget.removeTab(current_tab)
202 202 elif keepkernel: #close console but leave kernel running (no prompt)
203 203 self.tab_widget.removeTab(current_tab)
204 204 if kernel_manager and kernel_manager.channels_running:
205 205 kernel_manager.stop_channels()
206 206 else: #close console and kernel (no prompt)
207 207 self.tab_widget.removeTab(current_tab)
208 208 if kernel_manager and kernel_manager.channels_running:
209 209 kernel_manager.shutdown_kernel()
210 210 for slave in slave_tabs:
211 211 slave.kernel_manager.stop_channels()
212 212 self.tab_widget.removeTab(self.tab_widget.indexOf(slave))
213 213
214 214 self.update_tab_bar_visibility()
215 215
216 216 def add_tab_with_frontend(self,frontend,name=None):
217 217 """ insert a tab with a given frontend in the tab bar, and give it a name
218 218
219 219 """
220 220 if not name:
221 221 name=str('kernel '+str(self.tab_widget.count()))
222 222 self.tab_widget.addTab(frontend,name)
223 223 self.update_tab_bar_visibility()
224 224 self.make_frontend_visible(frontend)
225 225 frontend.exit_requested.connect(self.close_tab)
226 226
227 227 def next_tab(self):
228 228 self.tab_widget.setCurrentIndex((self.tab_widget.currentIndex()+1))
229 229
230 230 def prev_tab(self):
231 231 self.tab_widget.setCurrentIndex((self.tab_widget.currentIndex()-1))
232 232
233 233 def make_frontend_visible(self,frontend):
234 234 widget_index=self.tab_widget.indexOf(frontend)
235 235 if widget_index > 0 :
236 236 self.tab_widget.setCurrentIndex(widget_index)
237 237
238 238 def find_master_tab(self,tab,as_list=False):
239 239 """
240 240 Try to return the frontend that own the kernel attached to the given widget/tab.
241 241
242 242 Only find frontend owed by the current application. Selection
243 243 based on port of the kernel, might be inacurate if several kernel
244 244 on different ip use same port number.
245 245
246 246 This fonction does the conversion tabNumber/widget if needed.
247 247 Might return None if no master widget (non local kernel)
248 248 Will crash IPython if more than 1 masterWidget
249 249
250 250 When asList set to True, always return a list of widget(s) owning
251 251 the kernel. The list might be empty or containing several Widget.
252 252 """
253 253
254 254 #convert from/to int/richIpythonWidget if needed
255 255 if isinstance(tab, int):
256 256 tab = self.tab_widget.widget(tab)
257 257 km=tab.kernel_manager
258 258
259 259 #build list of all widgets
260 260 widget_list = [self.tab_widget.widget(i) for i in range(self.tab_widget.count())]
261 261
262 262 # widget that are candidate to be the owner of the kernel does have all the same port of the curent widget
263 263 # And should have a _may_close attribute
264 264 filtered_widget_list = [ widget for widget in widget_list if
265 265 widget.kernel_manager.connection_file == km.connection_file and
266 266 hasattr(widget,'_may_close') ]
267 267 # the master widget is the one that may close the kernel
268 268 master_widget= [ widget for widget in filtered_widget_list if widget._may_close]
269 269 if as_list:
270 270 return master_widget
271 271 assert(len(master_widget)<=1 )
272 272 if len(master_widget)==0:
273 273 return None
274 274
275 275 return master_widget[0]
276 276
277 277 def find_slave_widgets(self,tab):
278 278 """return all the frontends that do not own the kernel attached to the given widget/tab.
279 279
280 280 Only find frontends owned by the current application. Selection
281 281 based on connection file of the kernel.
282 282
283 283 This function does the conversion tabNumber/widget if needed.
284 284 """
285 285 #convert from/to int/richIpythonWidget if needed
286 286 if isinstance(tab, int):
287 287 tab = self.tab_widget.widget(tab)
288 288 km=tab.kernel_manager
289 289
290 290 #build list of all widgets
291 291 widget_list = [self.tab_widget.widget(i) for i in range(self.tab_widget.count())]
292 292
293 293 # widget that are candidate not to be the owner of the kernel does have all the same port of the curent widget
294 294 filtered_widget_list = ( widget for widget in widget_list if
295 295 widget.kernel_manager.connection_file == km.connection_file)
296 296 # Get a list of all widget owning the same kernel and removed it from
297 297 # the previous cadidate. (better using sets ?)
298 298 master_widget_list = self.find_master_tab(tab, as_list=True)
299 299 slave_list = [widget for widget in filtered_widget_list if widget not in master_widget_list]
300 300
301 301 return slave_list
302 302
303 303 # Populate the menu bar with common actions and shortcuts
304 304 def add_menu_action(self, menu, action):
305 305 """Add action to menu as well as self
306 306
307 307 So that when the menu bar is invisible, its actions are still available.
308 308 """
309 309 menu.addAction(action)
310 310 self.addAction(action)
311 311
312 312 def init_menu_bar(self):
313 313 #create menu in the order they should appear in the menu bar
314 314 self.init_file_menu()
315 315 self.init_edit_menu()
316 316 self.init_view_menu()
317 317 self.init_kernel_menu()
318 318 self.init_magic_menu()
319 319 self.init_window_menu()
320 320 self.init_help_menu()
321 321
322 322 def init_file_menu(self):
323 323 self.file_menu = self.menuBar().addMenu("&File")
324 324
325 325 self.new_kernel_tab_act = QtGui.QAction("New Tab with &New kernel",
326 326 self,
327 327 shortcut="Ctrl+T",
328 328 triggered=self.create_tab_with_new_frontend)
329 329 self.add_menu_action(self.file_menu, self.new_kernel_tab_act)
330 330
331 331 self.slave_kernel_tab_act = QtGui.QAction("New Tab with Sa&me kernel",
332 332 self,
333 333 shortcut="Ctrl+Shift+T",
334 334 triggered=self.create_tab_with_current_kernel)
335 335 self.add_menu_action(self.file_menu, self.slave_kernel_tab_act)
336 336
337 337 self.file_menu.addSeparator()
338 338
339 339 self.close_action=QtGui.QAction("&Close Tab",
340 340 self,
341 341 shortcut="Ctrl+W",
342 342 triggered=self.close_active_frontend
343 343 )
344 344 self.add_menu_action(self.file_menu, self.close_action)
345 345
346 346 self.export_action=QtGui.QAction("&Save to HTML/XHTML",
347 347 self,
348 348 shortcut="Ctrl+S",
349 349 triggered=self.export_action_active_frontend
350 350 )
351 351 self.add_menu_action(self.file_menu, self.export_action)
352 352
353 353 self.file_menu.addSeparator()
354 354
355 355 # Ctrl actually maps to Cmd on OSX, which avoids conflict with history
356 356 # action, which is already bound to true Ctrl+P
357 357 print_shortcut = "Ctrl+P" if sys.platform == 'darwin' else 'Ctrl+Shift+P'
358 358 self.print_action = QtGui.QAction("&Print",
359 359 self,
360 360 shortcut=print_shortcut,
361 361 triggered=self.print_action_active_frontend)
362 362 self.add_menu_action(self.file_menu, self.print_action)
363 363
364 if sys.platform == 'darwin':
364 if sys.platform != 'darwin':
365 365 # OSX always has Quit in the Application menu, only add it
366 366 # to the File menu elsewhere.
367 367
368 368 self.file_menu.addSeparator()
369 369
370 370 self.quit_action = QtGui.QAction("&Quit",
371 371 self,
372 372 shortcut=QtGui.QKeySequence.Quit,
373 373 triggered=self.close,
374 374 )
375 375 self.add_menu_action(self.file_menu, self.quit_action)
376 376
377 377
378 378 def init_edit_menu(self):
379 379 self.edit_menu = self.menuBar().addMenu("&Edit")
380 380
381 381 self.undo_action = QtGui.QAction("&Undo",
382 382 self,
383 383 shortcut="Ctrl+Z",
384 384 statusTip="Undo last action if possible",
385 385 triggered=self.undo_active_frontend
386 386 )
387 387 self.add_menu_action(self.edit_menu, self.undo_action)
388 388
389 389 self.redo_action = QtGui.QAction("&Redo",
390 390 self,
391 391 shortcut="Ctrl+Shift+Z",
392 392 statusTip="Redo last action if possible",
393 393 triggered=self.redo_active_frontend)
394 394 self.add_menu_action(self.edit_menu, self.redo_action)
395 395
396 396 self.edit_menu.addSeparator()
397 397
398 398 self.cut_action = QtGui.QAction("&Cut",
399 399 self,
400 400 shortcut=QtGui.QKeySequence.Cut,
401 401 triggered=self.cut_active_frontend
402 402 )
403 403 self.add_menu_action(self.edit_menu, self.cut_action)
404 404
405 405 self.copy_action = QtGui.QAction("&Copy",
406 406 self,
407 407 shortcut=QtGui.QKeySequence.Copy,
408 408 triggered=self.copy_active_frontend
409 409 )
410 410 self.add_menu_action(self.edit_menu, self.copy_action)
411 411
412 412 self.copy_raw_action = QtGui.QAction("Copy (&Raw Text)",
413 413 self,
414 414 shortcut="Ctrl+Shift+C",
415 415 triggered=self.copy_raw_active_frontend
416 416 )
417 417 self.add_menu_action(self.edit_menu, self.copy_raw_action)
418 418
419 419 self.paste_action = QtGui.QAction("&Paste",
420 420 self,
421 421 shortcut=QtGui.QKeySequence.Paste,
422 422 triggered=self.paste_active_frontend
423 423 )
424 424 self.add_menu_action(self.edit_menu, self.paste_action)
425 425
426 426 self.edit_menu.addSeparator()
427 427
428 428 self.select_all_action = QtGui.QAction("Select &All",
429 429 self,
430 430 shortcut="Ctrl+A",
431 431 triggered=self.select_all_active_frontend
432 432 )
433 433 self.add_menu_action(self.edit_menu, self.select_all_action)
434 434
435 435
436 436 def init_view_menu(self):
437 437 self.view_menu = self.menuBar().addMenu("&View")
438 438
439 439 if sys.platform != 'darwin':
440 440 # disable on OSX, where there is always a menu bar
441 441 self.toggle_menu_bar_act = QtGui.QAction("Toggle &Menu Bar",
442 442 self,
443 443 shortcut="Ctrl+Shift+M",
444 444 statusTip="Toggle visibility of menubar",
445 445 triggered=self.toggle_menu_bar)
446 446 self.add_menu_action(self.view_menu, self.toggle_menu_bar_act)
447 447
448 448 fs_key = "Ctrl+Meta+F" if sys.platform == 'darwin' else "F11"
449 449 self.full_screen_act = QtGui.QAction("&Full Screen",
450 450 self,
451 451 shortcut=fs_key,
452 452 statusTip="Toggle between Fullscreen and Normal Size",
453 453 triggered=self.toggleFullScreen)
454 454 self.add_menu_action(self.view_menu, self.full_screen_act)
455 455
456 456 self.view_menu.addSeparator()
457 457
458 458 self.increase_font_size = QtGui.QAction("Zoom &In",
459 459 self,
460 460 shortcut="Ctrl++",
461 461 triggered=self.increase_font_size_active_frontend
462 462 )
463 463 self.add_menu_action(self.view_menu, self.increase_font_size)
464 464
465 465 self.decrease_font_size = QtGui.QAction("Zoom &Out",
466 466 self,
467 467 shortcut="Ctrl+-",
468 468 triggered=self.decrease_font_size_active_frontend
469 469 )
470 470 self.add_menu_action(self.view_menu, self.decrease_font_size)
471 471
472 472 self.reset_font_size = QtGui.QAction("Zoom &Reset",
473 473 self,
474 474 shortcut="Ctrl+0",
475 475 triggered=self.reset_font_size_active_frontend
476 476 )
477 477 self.add_menu_action(self.view_menu, self.reset_font_size)
478 478
479 479 self.view_menu.addSeparator()
480 480
481 481 self.clear_action = QtGui.QAction("&Clear Screen",
482 482 self,
483 483 shortcut='Ctrl+L',
484 484 statusTip="Clear the console",
485 485 triggered=self.clear_magic_active_frontend)
486 486 self.add_menu_action(self.view_menu, self.clear_action)
487 487
488 488 def init_kernel_menu(self):
489 489 self.kernel_menu = self.menuBar().addMenu("&Kernel")
490 490 # Qt on OSX maps Ctrl to Cmd, and Meta to Ctrl
491 491 # keep the signal shortcuts to ctrl, rather than
492 492 # platform-default like we do elsewhere.
493 493
494 494 ctrl = "Meta" if sys.platform == 'darwin' else "Ctrl"
495 495
496 496 self.interrupt_kernel_action = QtGui.QAction("Interrupt current Kernel",
497 497 self,
498 498 triggered=self.interrupt_kernel_active_frontend,
499 499 shortcut=ctrl+"+C",
500 500 )
501 501 self.add_menu_action(self.kernel_menu, self.interrupt_kernel_action)
502 502
503 503 self.restart_kernel_action = QtGui.QAction("Restart current Kernel",
504 504 self,
505 505 triggered=self.restart_kernel_active_frontend,
506 506 shortcut=ctrl+"+.",
507 507 )
508 508 self.add_menu_action(self.kernel_menu, self.restart_kernel_action)
509 509
510 510 self.kernel_menu.addSeparator()
511 511
512 512 def init_magic_menu(self):
513 513 self.magic_menu = self.menuBar().addMenu("&Magic")
514 514 self.all_magic_menu = self.magic_menu.addMenu("&All Magics")
515 515
516 516 self.reset_action = QtGui.QAction("&Reset",
517 517 self,
518 518 statusTip="Clear all varible from workspace",
519 519 triggered=self.reset_magic_active_frontend)
520 520 self.add_menu_action(self.magic_menu, self.reset_action)
521 521
522 522 self.history_action = QtGui.QAction("&History",
523 523 self,
524 524 statusTip="show command history",
525 525 triggered=self.history_magic_active_frontend)
526 526 self.add_menu_action(self.magic_menu, self.history_action)
527 527
528 528 self.save_action = QtGui.QAction("E&xport History ",
529 529 self,
530 530 statusTip="Export History as Python File",
531 531 triggered=self.save_magic_active_frontend)
532 532 self.add_menu_action(self.magic_menu, self.save_action)
533 533
534 534 self.who_action = QtGui.QAction("&Who",
535 535 self,
536 536 statusTip="List interactive variable",
537 537 triggered=self.who_magic_active_frontend)
538 538 self.add_menu_action(self.magic_menu, self.who_action)
539 539
540 540 self.who_ls_action = QtGui.QAction("Wh&o ls",
541 541 self,
542 542 statusTip="Return a list of interactive variable",
543 543 triggered=self.who_ls_magic_active_frontend)
544 544 self.add_menu_action(self.magic_menu, self.who_ls_action)
545 545
546 546 self.whos_action = QtGui.QAction("Who&s",
547 547 self,
548 548 statusTip="List interactive variable with detail",
549 549 triggered=self.whos_magic_active_frontend)
550 550 self.add_menu_action(self.magic_menu, self.whos_action)
551 551
552 552 # allmagics submenu:
553 553
554 554 #for now this is just a copy and paste, but we should get this dynamically
555 555 magiclist=["%alias", "%autocall", "%automagic", "%bookmark", "%cd", "%clear",
556 556 "%colors", "%debug", "%dhist", "%dirs", "%doctest_mode", "%ed", "%edit", "%env", "%gui",
557 557 "%guiref", "%hist", "%history", "%install_default_config", "%install_profiles",
558 558 "%less", "%load_ext", "%loadpy", "%logoff", "%logon", "%logstart", "%logstate",
559 559 "%logstop", "%lsmagic", "%macro", "%magic", "%man", "%more", "%notebook", "%page",
560 560 "%pastebin", "%pdb", "%pdef", "%pdoc", "%pfile", "%pinfo", "%pinfo2", "%popd", "%pprint",
561 561 "%precision", "%profile", "%prun", "%psearch", "%psource", "%pushd", "%pwd", "%pycat",
562 562 "%pylab", "%quickref", "%recall", "%rehashx", "%reload_ext", "%rep", "%rerun",
563 563 "%reset", "%reset_selective", "%run", "%save", "%sc", "%sx", "%tb", "%time", "%timeit",
564 564 "%unalias", "%unload_ext", "%who", "%who_ls", "%whos", "%xdel", "%xmode"]
565 565
566 566 def make_dynamic_magic(i):
567 567 def inner_dynamic_magic():
568 568 self.active_frontend.execute(i)
569 569 inner_dynamic_magic.__name__ = "dynamics_magic_%s" % i
570 570 return inner_dynamic_magic
571 571
572 572 for magic in magiclist:
573 573 xaction = QtGui.QAction(magic,
574 574 self,
575 575 triggered=make_dynamic_magic(magic)
576 576 )
577 577 self.all_magic_menu.addAction(xaction)
578 578
579 579 def init_window_menu(self):
580 580 self.window_menu = self.menuBar().addMenu("&Window")
581 581 if sys.platform == 'darwin':
582 582 # add min/maximize actions to OSX, which lacks default bindings.
583 583 self.minimizeAct = QtGui.QAction("Mini&mize",
584 584 self,
585 585 shortcut="Ctrl+m",
586 586 statusTip="Minimize the window/Restore Normal Size",
587 587 triggered=self.toggleMinimized)
588 588 # maximize is called 'Zoom' on OSX for some reason
589 589 self.maximizeAct = QtGui.QAction("&Zoom",
590 590 self,
591 591 shortcut="Ctrl+Shift+M",
592 592 statusTip="Maximize the window/Restore Normal Size",
593 593 triggered=self.toggleMaximized)
594 594
595 595 self.add_menu_action(self.window_menu, self.minimizeAct)
596 596 self.add_menu_action(self.window_menu, self.maximizeAct)
597 597 self.window_menu.addSeparator()
598 598
599 599 prev_key = "Ctrl+Shift+Left" if sys.platform == 'darwin' else "Ctrl+PgUp"
600 600 self.prev_tab_act = QtGui.QAction("Pre&vious Tab",
601 601 self,
602 602 shortcut=prev_key,
603 603 statusTip="Select previous tab",
604 604 triggered=self.prev_tab)
605 605 self.add_menu_action(self.window_menu, self.prev_tab_act)
606 606
607 607 next_key = "Ctrl+Shift+Right" if sys.platform == 'darwin' else "Ctrl+PgDown"
608 608 self.next_tab_act = QtGui.QAction("Ne&xt Tab",
609 609 self,
610 610 shortcut=next_key,
611 611 statusTip="Select next tab",
612 612 triggered=self.next_tab)
613 613 self.add_menu_action(self.window_menu, self.next_tab_act)
614 614
615 615 def init_help_menu(self):
616 616 # please keep the Help menu in Mac Os even if empty. It will
617 617 # automatically contain a search field to search inside menus and
618 618 # please keep it spelled in English, as long as Qt Doesn't support
619 619 # a QAction.MenuRole like HelpMenuRole otherwise it will loose
620 620 # this search field fonctionality
621 621
622 622 self.help_menu = self.menuBar().addMenu("&Help")
623 623
624 624
625 625 # Help Menu
626 626
627 627 self.intro_active_frontend_action = QtGui.QAction("&Intro to IPython",
628 628 self,
629 629 triggered=self.intro_active_frontend
630 630 )
631 631 self.add_menu_action(self.help_menu, self.intro_active_frontend_action)
632 632
633 633 self.quickref_active_frontend_action = QtGui.QAction("IPython &Cheat Sheet",
634 634 self,
635 635 triggered=self.quickref_active_frontend
636 636 )
637 637 self.add_menu_action(self.help_menu, self.quickref_active_frontend_action)
638 638
639 639 self.guiref_active_frontend_action = QtGui.QAction("&Qt Console",
640 640 self,
641 641 triggered=self.guiref_active_frontend
642 642 )
643 643 self.add_menu_action(self.help_menu, self.guiref_active_frontend_action)
644 644
645 645 self.onlineHelpAct = QtGui.QAction("Open Online &Help",
646 646 self,
647 647 triggered=self._open_online_help)
648 648 self.add_menu_action(self.help_menu, self.onlineHelpAct)
649 649
650 650 # minimize/maximize/fullscreen actions:
651 651
652 652 def toggle_menu_bar(self):
653 653 menu_bar = self.menuBar()
654 654 if menu_bar.isVisible():
655 655 menu_bar.setVisible(False)
656 656 else:
657 657 menu_bar.setVisible(True)
658 658
659 659 def toggleMinimized(self):
660 660 if not self.isMinimized():
661 661 self.showMinimized()
662 662 else:
663 663 self.showNormal()
664 664
665 665 def _open_online_help(self):
666 666 filename="http://ipython.org/ipython-doc/stable/index.html"
667 667 webbrowser.open(filename, new=1, autoraise=True)
668 668
669 669 def toggleMaximized(self):
670 670 if not self.isMaximized():
671 671 self.showMaximized()
672 672 else:
673 673 self.showNormal()
674 674
675 675 # Min/Max imizing while in full screen give a bug
676 676 # when going out of full screen, at least on OSX
677 677 def toggleFullScreen(self):
678 678 if not self.isFullScreen():
679 679 self.showFullScreen()
680 680 if sys.platform == 'darwin':
681 681 self.maximizeAct.setEnabled(False)
682 682 self.minimizeAct.setEnabled(False)
683 683 else:
684 684 self.showNormal()
685 685 if sys.platform == 'darwin':
686 686 self.maximizeAct.setEnabled(True)
687 687 self.minimizeAct.setEnabled(True)
688 688
689 689 def close_active_frontend(self):
690 690 self.close_tab(self.active_frontend)
691 691
692 692 def restart_kernel_active_frontend(self):
693 693 self.active_frontend.request_restart_kernel()
694 694
695 695 def interrupt_kernel_active_frontend(self):
696 696 self.active_frontend.request_interrupt_kernel()
697 697
698 698 def cut_active_frontend(self):
699 699 self.active_frontend.cut_action.trigger()
700 700
701 701 def copy_active_frontend(self):
702 702 self.active_frontend.copy_action.trigger()
703 703
704 704 def copy_raw_active_frontend(self):
705 705 self.active_frontend._copy_raw_action.trigger()
706 706
707 707 def paste_active_frontend(self):
708 708 self.active_frontend.paste_action.trigger()
709 709
710 710 def undo_active_frontend(self):
711 711 self.active_frontend.undo()
712 712
713 713 def redo_active_frontend(self):
714 714 self.active_frontend.redo()
715 715
716 716 def reset_magic_active_frontend(self):
717 717 self.active_frontend.execute("%reset")
718 718
719 719 def history_magic_active_frontend(self):
720 720 self.active_frontend.execute("%history")
721 721
722 722 def save_magic_active_frontend(self):
723 723 self.active_frontend.save_magic()
724 724
725 725 def clear_magic_active_frontend(self):
726 726 self.active_frontend.execute("%clear")
727 727
728 728 def who_magic_active_frontend(self):
729 729 self.active_frontend.execute("%who")
730 730
731 731 def who_ls_magic_active_frontend(self):
732 732 self.active_frontend.execute("%who_ls")
733 733
734 734 def whos_magic_active_frontend(self):
735 735 self.active_frontend.execute("%whos")
736 736
737 737 def print_action_active_frontend(self):
738 738 self.active_frontend.print_action.trigger()
739 739
740 740 def export_action_active_frontend(self):
741 741 self.active_frontend.export_action.trigger()
742 742
743 743 def select_all_active_frontend(self):
744 744 self.active_frontend.select_all_action.trigger()
745 745
746 746 def increase_font_size_active_frontend(self):
747 747 self.active_frontend.increase_font_size.trigger()
748 748
749 749 def decrease_font_size_active_frontend(self):
750 750 self.active_frontend.decrease_font_size.trigger()
751 751
752 752 def reset_font_size_active_frontend(self):
753 753 self.active_frontend.reset_font_size.trigger()
754 754
755 755 def guiref_active_frontend(self):
756 756 self.active_frontend.execute("%guiref")
757 757
758 758 def intro_active_frontend(self):
759 759 self.active_frontend.execute("?")
760 760
761 761 def quickref_active_frontend(self):
762 762 self.active_frontend.execute("%quickref")
763 763 #---------------------------------------------------------------------------
764 764 # QWidget interface
765 765 #---------------------------------------------------------------------------
766 766
767 767 def closeEvent(self, event):
768 768 """ Forward the close event to every tabs contained by the windows
769 769 """
770 770 if self.tab_widget.count() == 0:
771 771 # no tabs, just close
772 772 event.accept()
773 773 return
774 774 # Do Not loop on the widget count as it change while closing
775 775 title = self.window().windowTitle()
776 776 cancel = QtGui.QMessageBox.Cancel
777 777 okay = QtGui.QMessageBox.Ok
778 778
779 779 if self.confirm_exit:
780 780 msg = "Close all tabs, stop all kernels, and Quit?"
781 781 closeall = QtGui.QPushButton("&Yes, quit everything", self)
782 782 closeall.setShortcut('Y')
783 783 box = QtGui.QMessageBox(QtGui.QMessageBox.Question,
784 784 title, msg)
785 785 # box.setInformativeText(info)
786 786 box.addButton(cancel)
787 787 box.addButton(closeall, QtGui.QMessageBox.YesRole)
788 788 box.setDefaultButton(closeall)
789 789 box.setEscapeButton(cancel)
790 790 pixmap = QtGui.QPixmap(self._app.icon.pixmap(QtCore.QSize(64,64)))
791 791 box.setIconPixmap(pixmap)
792 792 reply = box.exec_()
793 793 else:
794 794 reply = okay
795 795
796 796 if reply == cancel:
797 797 return
798 798 if reply == okay:
799 799 while self.tab_widget.count() >= 1:
800 800 # prevent further confirmations:
801 801 widget = self.active_frontend
802 802 widget._confirm_exit = False
803 803 self.close_tab(widget)
804 804
805 805 event.accept()
806 806
General Comments 0
You need to be logged in to leave comments. Login now