1 # copyright 1997-2001 Just van Rossum, Letterror. just@letterror.com
12 from Carbon
import File
13 from Carbon
import Files
15 if MacOS
.runtimemodel
== 'macho':
21 from gestalt
import gestalt
22 gestaltMenuMgrAquaLayoutBit
= 1 # menus have the Aqua 1.0 layout
23 gestaltMenuMgrAquaLayoutMask
= (1L << gestaltMenuMgrAquaLayoutBit
)
24 value
= gestalt("menu") & gestaltMenuMgrAquaLayoutMask
28 file = File
.FSRef(file)
29 catinfo
, d1
, d2
, d3
= file.FSGetCatalogInfo(Files
.kFSCatInfoContentMod
)
30 return catinfo
.contentModDate
32 class PythonIDE(Wapplication
.Application
):
35 self
.preffilepath
= os
.path
.join("Python", "PythonIDE preferences")
36 Wapplication
.Application
.__init
__(self
, 'Pide')
38 from Carbon
import AppleEvents
40 AE
.AEInstallEventHandler(AppleEvents
.kCoreEventClass
, AppleEvents
.kAEOpenApplication
,
42 AE
.AEInstallEventHandler(AppleEvents
.kCoreEventClass
, AppleEvents
.kAEReopenApplication
,
44 AE
.AEInstallEventHandler(AppleEvents
.kCoreEventClass
, AppleEvents
.kAEPrintDocuments
,
46 AE
.AEInstallEventHandler(AppleEvents
.kCoreEventClass
, AppleEvents
.kAEOpenDocuments
,
48 AE
.AEInstallEventHandler(AppleEvents
.kCoreEventClass
, AppleEvents
.kAEQuitApplication
,
50 import PyConsole
, PyEdit
52 if sys
.platform
== "darwin":
53 if sys
.argv
and sys
.argv
[0].startswith("-psn"):
54 home
= os
.getenv("HOME")
57 # With -D option (OSX command line only) keep stderr, for debugging the IDE
60 if len(sys
.argv
) >= 2 and sys
.argv
[1] == '-D':
61 debug_stderr
= sys
.stderr
63 PyConsole
.installoutput()
64 PyConsole
.installconsole()
66 sys
.stderr
= debug_stderr
67 for path
in sys
.argv
[1:]:
68 if path
.startswith("-p"):
69 # process number added by the OS
74 def makeusermenus(self
):
75 m
= Wapplication
.Menu(self
.menubar
, "File")
76 newitem
= FrameWork
.MenuItem(m
, "New", "N", 'new')
77 openitem
= FrameWork
.MenuItem(m
, "Open"+ELIPSES
, "O", 'open')
78 openbynameitem
= FrameWork
.MenuItem(m
, "Open File by Name"+ELIPSES
, "D", 'openbyname')
79 self
.openrecentmenu
= FrameWork
.SubMenu(m
, "Open Recent")
80 self
.makeopenrecentmenu()
81 FrameWork
.Separator(m
)
82 closeitem
= FrameWork
.MenuItem(m
, "Close", "W", 'close')
83 saveitem
= FrameWork
.MenuItem(m
, "Save", "S", 'save')
84 saveasitem
= FrameWork
.MenuItem(m
, "Save as"+ELIPSES
, None, 'save_as')
85 FrameWork
.Separator(m
)
86 saveasappletitem
= FrameWork
.MenuItem(m
, "Save as Applet"+ELIPSES
, None, 'save_as_applet')
87 FrameWork
.Separator(m
)
88 instmgritem
= FrameWork
.MenuItem(m
, "Package Manager", None, 'openpackagemanager')
89 gensuiteitem
= FrameWork
.MenuItem(m
, "Generate OSA Suite...", None, 'gensuite')
90 if not runningOnOSX():
91 # On OSX there's a special "magic" quit menu, so we shouldn't add
92 # it to the File menu.
93 FrameWork
.Separator(m
)
94 quititem
= FrameWork
.MenuItem(m
, "Quit", "Q", 'quit')
96 m
= Wapplication
.Menu(self
.menubar
, "Edit")
97 undoitem
= FrameWork
.MenuItem(m
, "Undo", 'Z', "undo")
98 FrameWork
.Separator(m
)
99 cutitem
= FrameWork
.MenuItem(m
, "Cut", 'X', "cut")
100 copyitem
= FrameWork
.MenuItem(m
, "Copy", "C", "copy")
101 pasteitem
= FrameWork
.MenuItem(m
, "Paste", "V", "paste")
102 FrameWork
.MenuItem(m
, "Clear", None, "clear")
103 FrameWork
.Separator(m
)
104 selallitem
= FrameWork
.MenuItem(m
, "Select all", "A", "selectall")
105 sellineitem
= FrameWork
.MenuItem(m
, "Select line", "L", "selectline")
106 FrameWork
.Separator(m
)
107 finditem
= FrameWork
.MenuItem(m
, "Find"+ELIPSES
, "F", "find")
108 findagainitem
= FrameWork
.MenuItem(m
, "Find again", 'G', "findnext")
109 enterselitem
= FrameWork
.MenuItem(m
, "Enter search string", "E", "entersearchstring")
110 replaceitem
= FrameWork
.MenuItem(m
, "Replace", None, "replace")
111 replacefinditem
= FrameWork
.MenuItem(m
, "Replace & find again", 'T', "replacefind")
112 FrameWork
.Separator(m
)
113 shiftleftitem
= FrameWork
.MenuItem(m
, "Shift left", "[", "shiftleft")
114 shiftrightitem
= FrameWork
.MenuItem(m
, "Shift right", "]", "shiftright")
116 m
= Wapplication
.Menu(self
.menubar
, "Python")
117 runitem
= FrameWork
.MenuItem(m
, "Run window", "R", 'run')
118 runselitem
= FrameWork
.MenuItem(m
, "Run selection", None, 'runselection')
119 FrameWork
.Separator(m
)
120 moditem
= FrameWork
.MenuItem(m
, "Module browser"+ELIPSES
, "M", self
.domenu_modulebrowser
)
121 FrameWork
.Separator(m
)
122 mm
= FrameWork
.SubMenu(m
, "Preferences")
123 FrameWork
.MenuItem(mm
, "Set Scripts folder"+ELIPSES
, None, self
.do_setscriptsfolder
)
124 FrameWork
.MenuItem(mm
, "Editor default settings"+ELIPSES
, None, self
.do_editorprefs
)
125 FrameWork
.MenuItem(mm
, "Set default window font"+ELIPSES
, None, self
.do_setwindowfont
)
127 self
.openwindowsmenu
= Wapplication
.Menu(self
.menubar
, 'Windows')
128 self
.makeopenwindowsmenu()
129 self
._menustocheck
= [closeitem
, saveitem
, saveasitem
, saveasappletitem
,
130 undoitem
, cutitem
, copyitem
, pasteitem
,
131 selallitem
, sellineitem
,
132 finditem
, findagainitem
, enterselitem
, replaceitem
, replacefinditem
,
133 shiftleftitem
, shiftrightitem
,
136 prefs
= self
.getprefs()
138 fsr
, d
= File
.Alias(rawdata
=prefs
.scriptsfolder
).FSResolveAlias(None)
139 self
.scriptsfolder
= fsr
.FSNewAliasMinimal()
141 path
= os
.path
.join(os
.getcwd(), "Mac", "IDE scripts")
142 if not os
.path
.exists(path
):
143 path
= os
.path
.join(os
.getcwd(), "Scripts")
144 if not os
.path
.exists(path
):
146 f
= open(os
.path
.join(path
, "Place your scripts here"+ELIPSES
), "w")
148 fsr
= File
.FSRef(path
)
149 self
.scriptsfolder
= fsr
.FSNewAliasMinimal()
150 self
.scriptsfoldermodtime
= getmodtime(fsr
)
152 self
.scriptsfoldermodtime
= getmodtime(fsr
)
153 prefs
.scriptsfolder
= self
.scriptsfolder
.data
155 self
.scriptsmenu
= None
156 self
.makescriptsmenu()
159 def quitevent(self
, theAppleEvent
, theReply
):
162 def suspendresume(self
, onoff
):
164 fsr
, changed
= self
.scriptsfolder
.FSResolveAlias(None)
165 modtime
= getmodtime(fsr
)
166 if self
.scriptsfoldermodtime
<> modtime
or changed
:
167 self
.scriptsfoldermodtime
= modtime
169 self
.makescriptsmenu()
171 def ignoreevent(self
, theAppleEvent
, theReply
):
174 def opendocsevent(self
, theAppleEvent
, theReply
):
177 parameters
, args
= aetools
.unpackevent(theAppleEvent
)
178 docs
= parameters
['----']
179 if type(docs
) <> type([]):
182 fsr
, a
= doc
.FSResolveAlias(None)
183 path
= fsr
.as_pathname()
186 def opendoc(self
, path
):
187 fcreator
, ftype
= MacOS
.GetCreatorAndType(path
)
189 self
.openscript(path
)
190 elif ftype
== '\0\0\0\0' and path
[-3:] == '.py':
191 self
.openscript(path
)
193 W
.Message("Can't open file of type '%s'." % ftype
)
195 def getabouttext(self
):
196 return "About Python IDE"+ELIPSES
198 def do_about(self
, id, item
, window
, event
):
201 def do_setscriptsfolder(self
, *args
):
202 fsr
= EasyDialogs
.AskFolder(message
="Select Scripts Folder",
205 prefs
= self
.getprefs()
206 alis
= fsr
.FSNewAliasMinimal()
207 prefs
.scriptsfolder
= alis
.data
208 self
.scriptsfolder
= alis
209 self
.makescriptsmenu()
212 def domenu_modulebrowser(self
, *args
):
215 ModuleBrowser
.ModuleBrowser()
217 def domenu_open(self
, *args
):
218 filename
= EasyDialogs
.AskFileForOpen(typeList
=("TEXT",))
220 self
.openscript(filename
)
222 def domenu_openbyname(self
, *args
):
223 # Open a file by name. If the clipboard contains a filename
224 # use that as the default.
225 from Carbon
import Scrap
227 sc
= Scrap
.GetCurrentScrap()
228 dft
= sc
.GetScrapFlavorData("TEXT")
232 if not os
.path
.exists(dft
):
234 filename
= EasyDialogs
.AskString("Open File Named:", default
=dft
, ok
="Open")
236 self
.openscript(filename
)
238 def domenu_new(self
, *args
):
241 return PyEdit
.Editor()
243 def makescriptsmenu(self
):
246 for id, item
in self
._scripts
.keys():
247 if self
.menubar
.menus
.has_key(id):
248 m
= self
.menubar
.menus
[id]
252 if hasattr(self
.scriptsmenu
, 'id') and self
.menubar
.menus
.has_key(self
.scriptsmenu
.id):
253 self
.scriptsmenu
.delete()
254 self
.scriptsmenu
= FrameWork
.Menu(self
.menubar
, "Scripts")
255 #FrameWork.MenuItem(self.scriptsmenu, "New script", None, self.domenu_new)
256 #self.scriptsmenu.addseparator()
257 fsr
, d1
= self
.scriptsfolder
.FSResolveAlias(None)
258 self
.scriptswalk(fsr
.as_pathname(), self
.scriptsmenu
)
260 def makeopenwindowsmenu(self
):
261 for i
in range(len(self
.openwindowsmenu
.items
)):
262 self
.openwindowsmenu
.menu
.DeleteMenuItem(1)
263 self
.openwindowsmenu
.items
= []
265 self
._openwindows
= {}
266 for window
in self
._windows
.keys():
267 title
= window
.GetWTitle()
270 windows
.append((title
, window
))
272 for title
, window
in windows
:
273 if title
== "Python Interactive": # ugly but useful hack by Joe Strout
277 item
= FrameWork
.MenuItem(self
.openwindowsmenu
, title
, shortcut
, callback
= self
.domenu_openwindows
)
278 self
._openwindows
[item
.item
] = window
279 self
._openwindowscheckmark
= 0
280 self
.checkopenwindowsmenu()
282 def makeopenrecentmenu(self
):
283 for i
in range(len(self
.openrecentmenu
.items
)):
284 self
.openrecentmenu
.menu
.DeleteMenuItem(1)
285 self
.openrecentmenu
.items
= []
286 prefs
= self
.getprefs()
287 filelist
= prefs
.recentfiles
289 self
.openrecentmenu
.enable(0)
291 self
.openrecentmenu
.enable(1)
292 for filename
in filelist
:
293 item
= FrameWork
.MenuItem(self
.openrecentmenu
, filename
, None, callback
= self
.domenu_openrecent
)
295 def addrecentfile(self
, file):
296 prefs
= self
.getprefs()
297 filelist
= prefs
.recentfiles
302 if file == filelist
[0]:
304 filelist
.remove(file)
305 filelist
.insert(0, file)
306 filelist
= filelist
[:10]
307 prefs
.recentfiles
= filelist
309 self
.makeopenrecentmenu()
311 def domenu_openwindows(self
, id, item
, window
, event
):
312 w
= self
._openwindows
[item
]
316 def domenu_openrecent(self
, id, item
, window
, event
):
317 prefs
= self
.getprefs()
318 filelist
= prefs
.recentfiles
322 filename
= filelist
[item
]
323 self
.openscript(filename
)
325 def domenu_quit(self
):
328 def domenu_save(self
, *args
):
332 import PyConsole
, PyEdit
333 for window
in self
._windows
.values():
335 rv
= window
.close() # ignore any errors while quitting
337 rv
= 0 # (otherwise, we can get stuck!)
341 PyConsole
.console
.writeprefs()
342 PyConsole
.output
.writeprefs()
343 PyEdit
.searchengine
.writeprefs()
345 # Write to __stderr__ so the msg end up in Console.app and has
346 # at least _some_ chance of getting read...
347 # But: this is a workaround for way more serious problems with
348 # the Python 2.2 Jaguar addon.
349 sys
.__stderr
__.write("*** PythonIDE: Can't write preferences ***\n")
352 def domenu_openpackagemanager(self
):
353 import PackageManager
354 PackageManager
.PackageBrowser()
356 def domenu_gensuite(self
):
357 import gensuitemodule
358 gensuitemodule
.main_interactive()
360 def makehelpmenu(self
):
361 hashelp
, hasdocs
= self
.installdocumentation()
362 self
.helpmenu
= m
= self
.gethelpmenu()
363 helpitem
= FrameWork
.MenuItem(m
, "MacPython Help", None, self
.domenu_localhelp
)
364 helpitem
.enable(hashelp
)
365 docitem
= FrameWork
.MenuItem(m
, "Python Documentation", None, self
.domenu_localdocs
)
366 docitem
.enable(hasdocs
)
367 finditem
= FrameWork
.MenuItem(m
, "Lookup in Python Documentation", None, 'lookuppython')
368 finditem
.enable(hasdocs
)
370 FrameWork
.Separator(m
)
371 doc2item
= FrameWork
.MenuItem(m
, "Apple Developer Documentation", None, self
.domenu_appledocs
)
372 find2item
= FrameWork
.MenuItem(m
, "Lookup in Carbon Documentation", None, 'lookupcarbon')
373 FrameWork
.Separator(m
)
374 webitem
= FrameWork
.MenuItem(m
, "Python Documentation on the Web", None, self
.domenu_webdocs
)
375 web2item
= FrameWork
.MenuItem(m
, "Python on the Web", None, self
.domenu_webpython
)
376 web3item
= FrameWork
.MenuItem(m
, "MacPython on the Web", None, self
.domenu_webmacpython
)
378 def domenu_localdocs(self
, *args
):
379 from Carbon
import AH
380 AH
.AHGotoPage("Python Documentation", None, None)
382 def domenu_localhelp(self
, *args
):
383 from Carbon
import AH
384 AH
.AHGotoPage("MacPython Help", None, None)
386 def domenu_appledocs(self
, *args
):
387 from Carbon
import AH
, AppleHelp
389 AH
.AHGotoMainTOC(AppleHelp
.kAHTOCTypeDeveloper
)
390 except AH
.Error
, arg
:
392 W
.Message("Developer documentation not installed")
394 W
.Message("AppleHelp Error: %s" % `arg`
)
396 def domenu_lookuppython(self
, *args
):
397 from Carbon
import AH
398 searchstring
= self
._getsearchstring
()
402 AH
.AHSearch("Python Documentation", searchstring
)
403 except AH
.Error
, arg
:
404 W
.Message("AppleHelp Error: %s" % `arg`
)
406 def domenu_lookupcarbon(self
, *args
):
407 from Carbon
import AH
408 searchstring
= self
._getsearchstring
()
412 AH
.AHSearch("Carbon", searchstring
)
413 except AH
.Error
, arg
:
414 W
.Message("AppleHelp Error: %s" % `arg`
)
416 def _getsearchstring(self
):
417 # First we get the frontmost window
418 front
= self
.getfrontwindow()
419 if front
and hasattr(front
, 'getselectedtext'):
420 text
= front
.getselectedtext()
423 # This is a cop-out. We should have disabled the menus
424 # if there is no selection, but the can_ methods only seem
425 # to work for Windows. Or not for the Help menu, maybe?
426 text
= EasyDialogs
.AskString("Search documentation for", ok
="Search")
429 def domenu_webdocs(self
, *args
):
431 major
, minor
, micro
, state
, nano
= sys
.version_info
432 if state
in ('alpha', 'beta'):
433 docversion
= 'dev/doc/devel'
435 docversion
= 'doc/%d.%d' % (major
, minor
)
437 docversion
= 'doc/%d.%d.%d' % (major
, minor
, micro
)
438 webbrowser
.open("http://www.python.org/%s" % docversion
)
440 def domenu_webpython(self
, *args
):
442 webbrowser
.open("http://www.python.org/")
444 def domenu_webmacpython(self
, *args
):
446 webbrowser
.open("http://www.cwi.nl/~jack/macpython.html")
448 def installdocumentation(self
):
449 # This is rather much of a hack. Someone has to tell the Help Viewer
450 # about the Python documentation, so why not us. The documentation
451 # is located in the framework, but there's a symlink in Python.app.
452 # And as AHRegisterHelpBook wants a bundle (with the right bits in
453 # the plist file) we refer it to Python.app
454 python_app
= os
.path
.join(sys
.prefix
, 'Resources/Python.app')
455 help_source
= os
.path
.join(python_app
, 'Contents/Resources/English.lproj/Documentation')
456 doc_source
= os
.path
.join(python_app
, 'Contents/Resources/English.lproj/PythonDocumentation')
457 has_help
= os
.path
.isdir(help_source
)
458 has_doc
= os
.path
.isdir(doc_source
)
459 if has_help
or has_doc
:
461 from Carbon
import AH
462 AH
.AHRegisterHelpBook(python_app
)
463 except (ImportError, MacOS
.Error
), arg
:
464 pass # W.Message("Cannot register Python Documentation: %s" % str(arg))
465 return has_help
, has_doc