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 if sys
.platform
== 'darwin':
89 instmgritem
= FrameWork
.MenuItem(m
, "Package Manager", None, 'openpackagemanager')
90 gensuiteitem
= FrameWork
.MenuItem(m
, "Generate OSA Suite...", None, 'gensuite')
91 if not runningOnOSX():
92 # On OSX there's a special "magic" quit menu, so we shouldn't add
93 # it to the File menu.
94 FrameWork
.Separator(m
)
95 quititem
= FrameWork
.MenuItem(m
, "Quit", "Q", 'quit')
97 m
= Wapplication
.Menu(self
.menubar
, "Edit")
98 undoitem
= FrameWork
.MenuItem(m
, "Undo", 'Z', "undo")
99 FrameWork
.Separator(m
)
100 cutitem
= FrameWork
.MenuItem(m
, "Cut", 'X', "cut")
101 copyitem
= FrameWork
.MenuItem(m
, "Copy", "C", "copy")
102 pasteitem
= FrameWork
.MenuItem(m
, "Paste", "V", "paste")
103 FrameWork
.MenuItem(m
, "Clear", None, "clear")
104 FrameWork
.Separator(m
)
105 selallitem
= FrameWork
.MenuItem(m
, "Select all", "A", "selectall")
106 sellineitem
= FrameWork
.MenuItem(m
, "Select line", "L", "selectline")
107 FrameWork
.Separator(m
)
108 finditem
= FrameWork
.MenuItem(m
, "Find"+ELIPSES
, "F", "find")
109 findagainitem
= FrameWork
.MenuItem(m
, "Find again", 'G', "findnext")
110 enterselitem
= FrameWork
.MenuItem(m
, "Enter search string", "E", "entersearchstring")
111 replaceitem
= FrameWork
.MenuItem(m
, "Replace", None, "replace")
112 replacefinditem
= FrameWork
.MenuItem(m
, "Replace & find again", 'T', "replacefind")
113 FrameWork
.Separator(m
)
114 shiftleftitem
= FrameWork
.MenuItem(m
, "Shift left", "[", "shiftleft")
115 shiftrightitem
= FrameWork
.MenuItem(m
, "Shift right", "]", "shiftright")
117 m
= Wapplication
.Menu(self
.menubar
, "Python")
118 runitem
= FrameWork
.MenuItem(m
, "Run window", "R", 'run')
119 runselitem
= FrameWork
.MenuItem(m
, "Run selection", None, 'runselection')
120 FrameWork
.Separator(m
)
121 moditem
= FrameWork
.MenuItem(m
, "Module browser"+ELIPSES
, "M", self
.domenu_modulebrowser
)
122 FrameWork
.Separator(m
)
123 mm
= FrameWork
.SubMenu(m
, "Preferences")
124 FrameWork
.MenuItem(mm
, "Set Scripts folder"+ELIPSES
, None, self
.do_setscriptsfolder
)
125 FrameWork
.MenuItem(mm
, "Editor default settings"+ELIPSES
, None, self
.do_editorprefs
)
126 FrameWork
.MenuItem(mm
, "Set default window font"+ELIPSES
, None, self
.do_setwindowfont
)
128 self
.openwindowsmenu
= Wapplication
.Menu(self
.menubar
, 'Windows')
129 self
.makeopenwindowsmenu()
130 self
._menustocheck
= [closeitem
, saveitem
, saveasitem
, saveasappletitem
,
131 undoitem
, cutitem
, copyitem
, pasteitem
,
132 selallitem
, sellineitem
,
133 finditem
, findagainitem
, enterselitem
, replaceitem
, replacefinditem
,
134 shiftleftitem
, shiftrightitem
,
137 prefs
= self
.getprefs()
139 fsr
, d
= File
.Alias(rawdata
=prefs
.scriptsfolder
).FSResolveAlias(None)
140 self
.scriptsfolder
= fsr
.FSNewAliasMinimal()
142 path
= os
.path
.join(os
.getcwd(), "Mac", "IDE scripts")
143 if not os
.path
.exists(path
):
144 path
= os
.path
.join(os
.getcwd(), "Scripts")
145 if not os
.path
.exists(path
):
147 f
= open(os
.path
.join(path
, "Place your scripts here"+ELIPSES
), "w")
149 fsr
= File
.FSRef(path
)
150 self
.scriptsfolder
= fsr
.FSNewAliasMinimal()
151 self
.scriptsfoldermodtime
= getmodtime(fsr
)
153 self
.scriptsfoldermodtime
= getmodtime(fsr
)
154 prefs
.scriptsfolder
= self
.scriptsfolder
.data
156 self
.scriptsmenu
= None
157 self
.makescriptsmenu()
160 def quitevent(self
, theAppleEvent
, theReply
):
163 def suspendresume(self
, onoff
):
165 fsr
, changed
= self
.scriptsfolder
.FSResolveAlias(None)
166 modtime
= getmodtime(fsr
)
167 if self
.scriptsfoldermodtime
<> modtime
or changed
:
168 self
.scriptsfoldermodtime
= modtime
170 self
.makescriptsmenu()
172 def ignoreevent(self
, theAppleEvent
, theReply
):
175 def opendocsevent(self
, theAppleEvent
, theReply
):
178 parameters
, args
= aetools
.unpackevent(theAppleEvent
)
179 docs
= parameters
['----']
180 if type(docs
) <> type([]):
183 fsr
, a
= doc
.FSResolveAlias(None)
184 path
= fsr
.as_pathname()
187 def opendoc(self
, path
):
188 fcreator
, ftype
= MacOS
.GetCreatorAndType(path
)
190 self
.openscript(path
)
191 elif ftype
== '\0\0\0\0' and path
[-3:] == '.py':
192 self
.openscript(path
)
194 W
.Message("Can't open file of type '%s'." % ftype
)
196 def getabouttext(self
):
197 return "About Python IDE"+ELIPSES
199 def do_about(self
, id, item
, window
, event
):
202 def do_setscriptsfolder(self
, *args
):
203 fsr
= EasyDialogs
.AskFolder(message
="Select Scripts Folder",
206 prefs
= self
.getprefs()
207 alis
= fsr
.FSNewAliasMinimal()
208 prefs
.scriptsfolder
= alis
.data
209 self
.scriptsfolder
= alis
210 self
.makescriptsmenu()
213 def domenu_modulebrowser(self
, *args
):
216 ModuleBrowser
.ModuleBrowser()
218 def domenu_open(self
, *args
):
219 filename
= EasyDialogs
.AskFileForOpen(typeList
=("TEXT",))
221 self
.openscript(filename
)
223 def domenu_openbyname(self
, *args
):
224 # Open a file by name. If the clipboard contains a filename
225 # use that as the default.
226 from Carbon
import Scrap
228 sc
= Scrap
.GetCurrentScrap()
229 dft
= sc
.GetScrapFlavorData("TEXT")
233 if not os
.path
.exists(dft
):
235 filename
= EasyDialogs
.AskString("Open File Named:", default
=dft
, ok
="Open")
237 self
.openscript(filename
)
239 def domenu_new(self
, *args
):
242 return PyEdit
.Editor()
244 def makescriptsmenu(self
):
247 for id, item
in self
._scripts
.keys():
248 if self
.menubar
.menus
.has_key(id):
249 m
= self
.menubar
.menus
[id]
253 if hasattr(self
.scriptsmenu
, 'id') and self
.menubar
.menus
.has_key(self
.scriptsmenu
.id):
254 self
.scriptsmenu
.delete()
255 self
.scriptsmenu
= FrameWork
.Menu(self
.menubar
, "Scripts")
256 #FrameWork.MenuItem(self.scriptsmenu, "New script", None, self.domenu_new)
257 #self.scriptsmenu.addseparator()
258 fsr
, d1
= self
.scriptsfolder
.FSResolveAlias(None)
259 self
.scriptswalk(fsr
.as_pathname(), self
.scriptsmenu
)
261 def makeopenwindowsmenu(self
):
262 for i
in range(len(self
.openwindowsmenu
.items
)):
263 self
.openwindowsmenu
.menu
.DeleteMenuItem(1)
264 self
.openwindowsmenu
.items
= []
266 self
._openwindows
= {}
267 for window
in self
._windows
.keys():
268 title
= window
.GetWTitle()
271 windows
.append((title
, window
))
273 for title
, window
in windows
:
274 if title
== "Python Interactive": # ugly but useful hack by Joe Strout
278 item
= FrameWork
.MenuItem(self
.openwindowsmenu
, title
, shortcut
, callback
= self
.domenu_openwindows
)
279 self
._openwindows
[item
.item
] = window
280 self
._openwindowscheckmark
= 0
281 self
.checkopenwindowsmenu()
283 def makeopenrecentmenu(self
):
284 for i
in range(len(self
.openrecentmenu
.items
)):
285 self
.openrecentmenu
.menu
.DeleteMenuItem(1)
286 self
.openrecentmenu
.items
= []
287 prefs
= self
.getprefs()
288 filelist
= prefs
.recentfiles
290 self
.openrecentmenu
.enable(0)
292 self
.openrecentmenu
.enable(1)
293 for filename
in filelist
:
294 item
= FrameWork
.MenuItem(self
.openrecentmenu
, filename
, None, callback
= self
.domenu_openrecent
)
296 def addrecentfile(self
, file):
297 prefs
= self
.getprefs()
298 filelist
= prefs
.recentfiles
303 if file == filelist
[0]:
305 filelist
.remove(file)
306 filelist
.insert(0, file)
307 filelist
= filelist
[:10]
308 prefs
.recentfiles
= filelist
310 self
.makeopenrecentmenu()
312 def domenu_openwindows(self
, id, item
, window
, event
):
313 w
= self
._openwindows
[item
]
317 def domenu_openrecent(self
, id, item
, window
, event
):
318 prefs
= self
.getprefs()
319 filelist
= prefs
.recentfiles
323 filename
= filelist
[item
]
324 self
.openscript(filename
)
326 def domenu_quit(self
):
329 def domenu_save(self
, *args
):
333 import PyConsole
, PyEdit
334 for window
in self
._windows
.values():
336 rv
= window
.close() # ignore any errors while quitting
338 rv
= 0 # (otherwise, we can get stuck!)
342 PyConsole
.console
.writeprefs()
343 PyConsole
.output
.writeprefs()
344 PyEdit
.searchengine
.writeprefs()
346 # Write to __stderr__ so the msg end up in Console.app and has
347 # at least _some_ chance of getting read...
348 # But: this is a workaround for way more serious problems with
349 # the Python 2.2 Jaguar addon.
350 sys
.__stderr
__.write("*** PythonIDE: Can't write preferences ***\n")
353 def domenu_openpackagemanager(self
):
354 import PackageManager
355 PackageManager
.PackageBrowser()
357 def domenu_gensuite(self
):
358 import gensuitemodule
359 gensuitemodule
.main_interactive()
361 def makehelpmenu(self
):
362 hashelp
, hasdocs
= self
.installdocumentation()
363 self
.helpmenu
= m
= self
.gethelpmenu()
364 helpitem
= FrameWork
.MenuItem(m
, "MacPython Help", None, self
.domenu_localhelp
)
365 helpitem
.enable(hashelp
)
366 docitem
= FrameWork
.MenuItem(m
, "Python Documentation", None, self
.domenu_localdocs
)
367 docitem
.enable(hasdocs
)
368 finditem
= FrameWork
.MenuItem(m
, "Lookup in Python Documentation", None, 'lookuppython')
369 finditem
.enable(hasdocs
)
371 FrameWork
.Separator(m
)
372 doc2item
= FrameWork
.MenuItem(m
, "Apple Developer Documentation", None, self
.domenu_appledocs
)
373 find2item
= FrameWork
.MenuItem(m
, "Lookup in Carbon Documentation", None, 'lookupcarbon')
374 FrameWork
.Separator(m
)
375 webitem
= FrameWork
.MenuItem(m
, "Python Documentation on the Web", None, self
.domenu_webdocs
)
376 web2item
= FrameWork
.MenuItem(m
, "Python on the Web", None, self
.domenu_webpython
)
377 web3item
= FrameWork
.MenuItem(m
, "MacPython on the Web", None, self
.domenu_webmacpython
)
379 def domenu_localdocs(self
, *args
):
380 from Carbon
import AH
381 AH
.AHGotoPage("Python Documentation", None, None)
383 def domenu_localhelp(self
, *args
):
384 from Carbon
import AH
385 AH
.AHGotoPage("MacPython Help", None, None)
387 def domenu_appledocs(self
, *args
):
388 from Carbon
import AH
, AppleHelp
390 AH
.AHGotoMainTOC(AppleHelp
.kAHTOCTypeDeveloper
)
391 except AH
.Error
, arg
:
393 W
.Message("Developer documentation not installed")
395 W
.Message("AppleHelp Error: %s" % `arg`
)
397 def domenu_lookuppython(self
, *args
):
398 from Carbon
import AH
399 searchstring
= self
._getsearchstring
()
403 AH
.AHSearch("Python Documentation", searchstring
)
404 except AH
.Error
, arg
:
405 W
.Message("AppleHelp Error: %s" % `arg`
)
407 def domenu_lookupcarbon(self
, *args
):
408 from Carbon
import AH
409 searchstring
= self
._getsearchstring
()
413 AH
.AHSearch("Carbon", searchstring
)
414 except AH
.Error
, arg
:
415 W
.Message("AppleHelp Error: %s" % `arg`
)
417 def _getsearchstring(self
):
419 editor
= PyEdit
.findeditor(None, fromtop
=1)
421 text
= editor
.getselectedtext()
424 # This is a cop-out. We should have disabled the menus
425 # if there is no selection, but the can_ methods only seem
426 # to work for Windows. Or not for the Help menu, maybe?
427 text
= EasyDialogs
.AskString("Search documentation for", ok
="Search")
430 def domenu_webdocs(self
, *args
):
432 major
, minor
, micro
, state
, nano
= sys
.version_info
433 if state
in ('alpha', 'beta'):
434 docversion
= 'dev/doc/devel'
436 docversion
= 'doc/%d.%d' % (major
, minor
)
438 docversion
= 'doc/%d.%d.%d' % (major
, minor
, micro
)
439 webbrowser
.open("http://www.python.org/%s" % docversion
)
441 def domenu_webpython(self
, *args
):
443 webbrowser
.open("http://www.python.org/")
445 def domenu_webmacpython(self
, *args
):
447 webbrowser
.open("http://www.cwi.nl/~jack/macpython.html")
449 def installdocumentation(self
):
450 # This is rather much of a hack. Someone has to tell the Help Viewer
451 # about the Python documentation, so why not us. The documentation
452 # is located in the framework, but there's a symlink in Python.app.
453 # And as AHRegisterHelpBook wants a bundle (with the right bits in
454 # the plist file) we refer it to Python.app
455 python_app
= os
.path
.join(sys
.prefix
, 'Resources/Python.app')
456 help_source
= os
.path
.join(python_app
, 'Contents/Resources/English.lproj/Documentation')
457 doc_source
= os
.path
.join(python_app
, 'Contents/Resources/English.lproj/PythonDocumentation')
458 has_help
= os
.path
.isdir(help_source
)
459 has_doc
= os
.path
.isdir(doc_source
)
460 if has_help
or has_doc
:
462 from Carbon
import AH
463 AH
.AHRegisterHelpBook(python_app
)
464 except (ImportError, MacOS
.Error
), arg
:
465 pass # W.Message("Cannot register Python Documentation: %s" % str(arg))
466 return has_help
, has_doc