##// END OF EJS Templates
Move Maigic Helper into separate class/module/file
Dimitry Kloper -
Show More
@@ -0,0 +1,179 b''
1 """Magic Helper - dockable widget showing magic commands for the MainWindow
2
3
4 Authors:
5
6 * Dimitry Kloper
7
8 """
9
10 #-----------------------------------------------------------------------------
11 # Imports
12 #-----------------------------------------------------------------------------
13
14 # stdlib imports
15 import json
16 import re
17 import sys
18
19 # System library imports
20 from IPython.external.qt import QtGui,QtCore
21
22 from IPython.core.magic import magic_escapes
23
24 class MagicHelper(QtGui.QDockWidget):
25
26 pasteRequested = QtCore.pyqtSignal(str, name = 'pasteRequested')
27 runRequested = QtCore.pyqtSignal(str, name = 'runRequested')
28
29 #---------------------------------------------------------------------------
30 # 'object' interface
31 #---------------------------------------------------------------------------
32
33 def __init__(self, name, parent):
34
35 super(MagicHelper, self).__init__(name, parent)
36
37 # this is a hack. The main_window reference will be used for
38 # explicit interface to kernel that must be hidden by signal/slot
39 # mechanism in the future
40 self.main_window = parent
41
42 self.data = None
43
44 class MinListWidget(QtGui.QListWidget):
45 def sizeHint(self):
46 s = QtCore.QSize()
47 s.setHeight(super(MinListWidget,self).sizeHint().height())
48 s.setWidth(self.sizeHintForColumn(0))
49 return s
50
51 self.frame = QtGui.QFrame()
52 self.search_label = QtGui.QLabel("Search:")
53 self.search_line = QtGui.QLineEdit()
54 self.search_class = QtGui.QComboBox()
55 self.search_list = MinListWidget()
56 self.paste_button = QtGui.QPushButton("Paste")
57 self.run_button = QtGui.QPushButton("Run")
58
59 main_layout = QtGui.QVBoxLayout()
60 search_layout = QtGui.QHBoxLayout()
61 search_layout.addWidget(self.search_label)
62 search_layout.addWidget(self.search_line, 10)
63 main_layout.addLayout(search_layout)
64 main_layout.addWidget(self.search_class)
65 main_layout.addWidget(self.search_list, 10)
66 action_layout = QtGui.QHBoxLayout()
67 action_layout.addWidget(self.paste_button)
68 action_layout.addWidget(self.run_button)
69 main_layout.addLayout(action_layout)
70
71 self.frame.setLayout(main_layout)
72 self.setWidget(self.frame)
73
74 self.visibilityChanged[bool].connect( self.update_magic_helper )
75 self.search_class.activated[int].connect(
76 self.class_selected
77 )
78 self.search_line.textChanged[str].connect(
79 self.search_changed
80 )
81 self.search_list.itemDoubleClicked[QtGui.QListWidgetItem].connect(
82 self.paste_requested
83 )
84 self.paste_button.clicked[bool].connect(
85 self.paste_requested
86 )
87 self.run_button.clicked[bool].connect(
88 self.run_requested
89 )
90
91 def update_magic_helper(self, visible):
92 if not visible or self.data != None:
93 return
94 self.data = {}
95 self.search_class.clear()
96 self.search_class.addItem("Populating...")
97 self.main_window.active_frontend._silent_exec_callback(
98 'get_ipython().magic("lsmagic")',
99 self.populate_magic_helper
100 )
101
102 def populate_magic_helper(self, data):
103 if not data:
104 return
105
106 if data['status'] != 'ok':
107 self.main_window.log.warn(
108 "%%lsmagic user-expression failed: {}".format(data)
109 )
110 return
111
112 self.search_class.clear()
113 self.search_list.clear()
114
115 self.data = json.loads(
116 data['data'].get('application/json', {})
117 )
118
119 self.search_class.addItem('All Magics', 'any')
120 classes = set()
121
122 for mtype in sorted(self.data):
123 subdict = self.data[mtype]
124 for name in sorted(subdict):
125 classes.add(subdict[name])
126
127 for cls in sorted(classes):
128 label = re.sub("([a-zA-Z]+)([A-Z][a-z])","\g<1> \g<2>", cls)
129 self.search_class.addItem(label, cls)
130
131 self.filter_magic_helper('.', 'any')
132
133 def class_selected(self, index):
134 item = self.search_class.itemData(index)
135 regex = self.search_line.text()
136 self.filter_magic_helper(regex = regex, cls = item)
137
138 def search_changed(self, search_string):
139 item = self.search_class.itemData(
140 self.search_class.currentIndex()
141 )
142 self.filter_magic_helper(regex = search_string, cls = item)
143
144 def _get_current_search_item(self, item = None):
145 text = None
146 if not isinstance(item, QtGui.QListWidgetItem):
147 item = self.search_list.currentItem()
148 text = item.text()
149 return text
150
151 def paste_requested(self, item = None):
152 text = self._get_current_search_item(item)
153 if text != None:
154 self.pasteRequested.emit(text)
155
156 def run_requested(self, item = None):
157 text = self._get_current_search_item(item)
158 if text != None:
159 self.runRequested.emit(text)
160
161 def filter_magic_helper(self, regex, cls):
162 if regex == "" or regex == None:
163 regex = '.'
164 if cls == None:
165 cls = 'any'
166
167 self.search_list.clear()
168 for mtype in sorted(self.data):
169 subdict = self.data[mtype]
170 prefix = magic_escapes[mtype]
171
172 for name in sorted(subdict):
173 mclass = subdict[name]
174 pmagic = prefix + name
175
176 if (re.match(regex, name) or re.match(regex, pmagic)) and \
177 (cls == 'any' or cls == mclass):
178 self.search_list.addItem(pmagic)
179
@@ -699,157 +699,39 b' class MainWindow(QtGui.QMainWindow):'
699 self.add_menu_action(self.help_menu, self.onlineHelpAct)
699 self.add_menu_action(self.help_menu, self.onlineHelpAct)
700
700
701 def init_magic_helper(self):
701 def init_magic_helper(self):
702 self.magic_helper_data = None
702 from .magic_helper import MagicHelper
703 self.magic_helper = QtGui.QDockWidget("Show Magics", self)
703
704 self.magic_helper = MagicHelper("Show Magics", self)
705
704 self.magic_helper.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea |
706 self.magic_helper.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea |
705 QtCore.Qt.RightDockWidgetArea)
707 QtCore.Qt.RightDockWidgetArea)
706 self.magic_helper.setVisible(False)
708 self.magic_helper.setVisible(False)
707
709
708 class MinListWidget(QtGui.QListWidget):
710 self.magic_helper.pasteRequested[str].connect(
709 def sizeHint(self):
710 s = QtCore.QSize()
711 s.setHeight(super(MinListWidget,self).sizeHint().height())
712 s.setWidth(self.sizeHintForColumn(0))
713 return s
714
715 self.magic_helper_frame = QtGui.QFrame()
716 self.magic_helper_searchl = QtGui.QLabel("Search:")
717 self.magic_helper_search = QtGui.QLineEdit()
718 self.magic_helper_class = QtGui.QComboBox()
719 self.magic_helper_list = MinListWidget()
720 self.magic_helper_paste = QtGui.QPushButton("Paste")
721 self.magic_helper_run = QtGui.QPushButton("Run")
722
723 main_layout = QtGui.QVBoxLayout()
724 search_layout = QtGui.QHBoxLayout()
725 search_layout.addWidget(self.magic_helper_searchl)
726 search_layout.addWidget(self.magic_helper_search, 10)
727 main_layout.addLayout(search_layout)
728 main_layout.addWidget(self.magic_helper_class)
729 main_layout.addWidget(self.magic_helper_list, 10)
730 action_layout = QtGui.QHBoxLayout()
731 action_layout.addWidget(self.magic_helper_paste)
732 action_layout.addWidget(self.magic_helper_run)
733 main_layout.addLayout(action_layout)
734
735 self.magic_helper_frame.setLayout(main_layout)
736 self.magic_helper.setWidget(self.magic_helper_frame)
737
738 self.magic_helper.visibilityChanged[bool].connect(
739 self.update_magic_helper
740 )
741 self.magic_helper_class.activated[int].connect(
742 self.magic_helper_class_selected
743 )
744 self.magic_helper_search.textChanged[str].connect(
745 self.magic_helper_search_changed
746 )
747 self.magic_helper_list.itemDoubleClicked[QtGui.QListWidgetItem].connect(
748 self.magic_helper_paste_requested
749 )
750 self.magic_helper_paste.clicked[bool].connect(
751 self.magic_helper_paste_requested
711 self.magic_helper_paste_requested
752 )
712 )
753 self.magic_helper_run.clicked[bool].connect(
713 self.magic_helper.runRequested[str].connect(
754 self.magic_helper_run_requested
714 self.magic_helper_run_requested
755 )
715 )
756
716
757 self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.magic_helper)
717 self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.magic_helper)
758
718
759 def update_magic_helper(self, visible):
760 if not visible or self.magic_helper_data != None:
761 return
762 self.magic_helper_data = {}
763 self.magic_helper_class.clear()
764 self.magic_helper_class.addItem("Populating...")
765 self.active_frontend._silent_exec_callback(
766 'get_ipython().magic("lsmagic")',
767 self.populate_magic_helper
768 )
769
770 def populate_magic_helper(self, data):
771 if not data:
772 return
773
774 if data['status'] != 'ok':
775 self.log.warn("%%lsmagic user-expression failed: {}".format(data))
776 return
777
778 self.magic_helper_class.clear()
779 self.magic_helper_list.clear()
780
781 self.magic_helper_data = json.loads(
782 data['data'].get('application/json', {})
783 )
784
785 self.magic_helper_class.addItem('All Magics', 'any')
786 classes = set()
787
788 for mtype in sorted(self.magic_helper_data):
789 subdict = self.magic_helper_data[mtype]
790 for name in sorted(subdict):
791 classes.add(subdict[name])
792
793 for cls in sorted(classes):
794 label = re.sub("([a-zA-Z]+)([A-Z][a-z])","\g<1> \g<2>", cls)
795 self.magic_helper_class.addItem(label, cls)
796
797 self.filter_magic_helper('.', 'any')
798
799 def magic_helper_class_selected(self, index):
800 item = self.magic_helper_class.itemData(index)
801 regex = self.magic_helper_search.text()
802 self.filter_magic_helper(regex = regex, cls = item)
803
804 def magic_helper_search_changed(self, search_string):
805 item = self.magic_helper_class.itemData(
806 self.magic_helper_class.currentIndex()
807 )
808 self.filter_magic_helper(regex = search_string, cls = item)
809
810 def _magic_helper_get_current(self, item = None):
811 text = None
812 if not isinstance(item, QtGui.QListWidgetItem):
813 item = self.magic_helper_list.currentItem()
814 text = item.text()
815 return text
816
817 def _set_active_frontend_focus(self):
719 def _set_active_frontend_focus(self):
818 # this is a hack, self.active_frontend._control seems to be
720 # this is a hack, self.active_frontend._control seems to be
819 # a private member. Unfortunately this is the only method
721 # a private member. Unfortunately this is the only method
820 # to set focus reliably
722 # to set focus reliably
821 QtCore.QTimer.singleShot(200, self.active_frontend._control.setFocus)
723 QtCore.QTimer.singleShot(200, self.active_frontend._control.setFocus)
822
724
823 def magic_helper_paste_requested(self, item = None):
725 def magic_helper_paste_requested(self, text = None):
824 text = self._magic_helper_get_current(item)
825 if text != None:
726 if text != None:
826 self.active_frontend.input_buffer = text
727 self.active_frontend.input_buffer = text
827 self._set_active_frontend_focus()
728 self._set_active_frontend_focus()
828
729
829 def magic_helper_run_requested(self, item = None):
730 def magic_helper_run_requested(self, text = None):
830 text = self._magic_helper_get_current(item)
831 if text != None:
731 if text != None:
832 self.active_frontend.execute(text)
732 self.active_frontend.execute(text)
833 self._set_active_frontend_focus()
733 self._set_active_frontend_focus()
834
734
835 def filter_magic_helper(self, regex, cls):
836 if regex == "" or regex == None:
837 regex = '.'
838 if cls == None:
839 cls = 'any'
840
841 self.magic_helper_list.clear()
842 for mtype in sorted(self.magic_helper_data):
843 subdict = self.magic_helper_data[mtype]
844 prefix = magic_escapes[mtype]
845
846 for name in sorted(subdict):
847 mclass = subdict[name]
848 pmagic = prefix + name
849
850 if (re.match(regex, name) or re.match(regex, pmagic)) and \
851 (cls == 'any' or cls == mclass):
852 self.magic_helper_list.addItem(pmagic)
853
735
854
736
855 # minimize/maximize/fullscreen actions:
737 # minimize/maximize/fullscreen actions:
General Comments 0
You need to be logged in to leave comments. Login now