import Tkinter, Pmw, tkFileDialog, base
from tkMessageBox import showerror,showinfo,askyesno
from tkSimpleDialog import askstring
import os, string, sys, project, version
root = None
directory_choices=['.']
directory_choices_map = {
'.':'Current directory'
}
class PyfortpGui:
"Create and Edit .pfp files."
balloon_text = \
"""pyfort -e creates a project file with a .pfp (PyFortProject) extension.
This is a text file which you can edit with Pyfort or with a text editor.
You can use the project file to compile and install a Pyfort extension.
Use the item on the Help menu to turn this balloon help on and off.
"""
command_summary = """\
Pyfort Project File Editor
The notebook has a page for each Pyfort module file.
You can switch from one page to the other by choosing a tab.
Buttons at the bottom:
New PYF -- Add a new Pyfort module to the project
Remove PYF -- Remove a Pyfort module from the project
Check -- Performs basic checks on the project.
Finish -- Save, exit editor.
Cancel -- Exit Pyfort without saving any changes.
"""
def __init__(self, p):
self.p = p # the project object
self.dialog = base.MyDialog(command=self.execute,
buttons=('New PYF', 'Remove PYF', 'Check', 'Finish', 'Cancel')
)
self.dialog.component('buttonbox').interior().configure(bg='light green')
base.balloon.bind(self.dialog.component('buttonbox'),
PyfortpGui.command_summary
)
base.balloon.bind(self.dialog.interior(), PyfortpGui.balloon_text)
self.dialog.withdraw()
# create the menus
main_menu = Pmw.MenuBar(self.dialog.interior(),
hull_relief = 'raised',
hull_borderwidth = 2,
balloon=base.balloon
)
main_menu.pack(side='top', fill='both')
self.create_filemenu(main_menu)
self.create_help_menu(main_menu)
self.create_forms(self.dialog.interior())
self._project2gui()
self.dialog.geometry("+50+50")
self.dialog.deiconify()
self.dialog.dialog.lift()
self.notebook.pack(expand=1, fill='both')
if not self.p.pyfs:
self.pyf_newfile()
else:
self.notebook.selectpage(0)
self.notebook.setnaturalsize()
def create_forms (self, parent):
self.mainframe = Tkinter.Frame(parent)
self.mainframe.pack(fill='both', expand=1)
self.notebook = Pmw.NoteBook(self.mainframe,
hull_borderwidth=3,
hull_highlightthickness=2,
tabpos='n'
)
self.notebook.component('hull').configure(bg='light blue')
base.balloon.bind(self.notebook,
"""First create your Pyfort file and then add it to the project using the
New PYF button. The name of the Pyfort file, less its ".pyf" extension,
will be the name used for the Fortran extension module it generates.
""")
def pyf_newfile (self):
self._gui2project()
here = os.getcwd()
dialog = tkFileDialog.Open(master=self.dialog.interior(),
filetypes=[('Pyfort input file', '*.pyf')],
title="Choose Pyfort Input File")
filename = dialog.show(initialdir=here)
if filename:
if filename in [x.filename for x in self.p.pyfs]:
showerror('Duplicate', 'That file is already in the project.')
return
filename = filename.replace(here+os.sep, '')
x = project.pyf(filename)
self.p.pyfs.append(x)
self._project2gui()
self.notebook.selectpage(x.name)
self.notebook.setnaturalsize()
def pyf_remove(self):
self._gui2project () # save what is there
page = self.notebook.getcurselection()
x = askyesno('Remove PYF?',
'Remove ' + page + "?")
if x:
self.p.pyfs = [y for y in self.p.pyfs if y.name != page]
self._project2gui()
def valid(self):
self._gui2project()
msg = self.p.validate()
if msg:
showerror('Project definition error', msg)
else:
showinfo('OK', 'Project checked ok.')
def _project2gui (self):
"Get the state from the project to the Gui"
self.set_title(self.p.filename)
for x in self.notebook.pagenames():
self.notebook.delete(x)
self.editors = {}
for x in self.p.pyfs:
page = self.notebook.insert(x.name, 0, tab_text=x.name)
editor = PyfEditor(page)
editor.put(x)
self.editors[x.name] = editor
def set_title(self, name):
title = "Pyfort Project Editor -- %s" % name
self.dialog.title(title)
def create_filemenu(self, main_menu):
main_menu.addmenu('File', 'Working with the PFP file',
side='left', tearoff = 0)
main_menu.addmenuitem('File', 'command',
'Save: save current values to file',
label = "Save",
command = self.save
)
main_menu.addmenuitem('File', 'command',
'Exit: exit the editor',
label = "Exit",
command = self.exit_editor_quick
)
def exit_editor_quick (self):
result = askyesno('Save?', "Save file?")
if result: self.save()
self.exit_editor (1-result)
def execute (self, name):
if name is None:
self.exit_editor_quick()
elif name == 'Finish':
self.save()
self.exit_editor(0)
elif name == 'Cancel':
self.exit_editor(1)
elif name == 'Check':
self.valid()
elif name == 'New PYF':
self.pyf_newfile()
elif name == 'Remove PYF':
self.pyf_remove()
def _gui2project (self):
self.p.pyfs = []
for e in self.editors.values():
self.p.pyfs.append(e.get())
def save(self):
self._gui2project()
try:
self.p.save()
except:
showerror('Project not saved.', 'An error prevented saving the project.')
def exit_editor(self, status):
"Invoked for exit and the cancel button"
self.dialog.dialog.destroy()
raise SystemExit, status
def create_help_menu( self, main_menu):
main_menu.addmenu('Help', PyfortpGui.command_summary,
side='right', tearoff = 1)
main_menu.addmenuitem('Help', 'command', 'Command Summary',
label = 'Command Summary',
command = self.evt_command_summary
)
base.add_balloon_help (main_menu, 'Help')
main_menu.addmenuitem('Help', 'separator')
main_menu.addmenuitem('Help', 'command', 'Help About',
label = 'About Pyfort',
command = self.evt_about_dialog
)
def evt_command_summary (self):
s = Pmw.TextDialog(self.dialog.interior(), title='Command summary')
s.transient(self.dialog.interior())
self.dialog.position_popup(s)
s.insert('end', PyfortpGui.command_summary)
def evt_about_dialog(self):
Pmw.aboutversion(version.version + " executed from " + sys.exec_prefix)
Pmw.aboutcopyright('Copyright:2001, Regents of the University of California\n')
Pmw.aboutcontact(
"""Go to pyfortran.sourceforge.net for documentation, support, bug reporting,
and releases.
""")
about = Pmw.AboutDialog(self.dialog.interior(),
applicationname = 'Pyfort')
about.transient(self.dialog.interior())
self.dialog.position_popup(about)
# Create/Popup contributor.
def create(filename):
p = project.project(filename)
PyfortpGui(p)
base.root().mainloop()
def _choice_key (choice, dict, name):
if not choice in dict.values():
dict[choice] = choice
for key, value in dict.items():
if value == choice: return key
freeform_options=['Free form','Column 1 convention']
class PyfEditor:
def __init__ (self, parent) :
self.parent = parent
self.filename = ''
self.show_advanced = 0
f1 = Tkinter.Frame(parent)
f1.pack(expand=1, fill='x', side='top', anchor='w')
w = Pmw.Group(f1)
self.g1 = w
w.pack(side='top', anchor='w', expand=1, fill='x')
self.generate_as_entry = Pmw.EntryField(w.interior(),
labelpos='w',
label_text='Generated Module Name',
value = ''
)
self.generate_as_entry.pack(side='top', anchor='w')
base.balloon.bind(self.generate_as_entry,
"""You can name the generated extension module here, but usually it is
the same as the name of the Pyfort module file.
""")
self.freeform_buttons = Pmw.RadioSelect(w.interior(),
buttontype = 'radiobutton',
orient = 'horizontal',
labelpos = 'w',
command = self.freeformcallback,
label_text = 'PYF File Format',
)
self.freeform_buttons.pack(side = 'top', anchor='w', expand = 1, fill='x')
for x in freeform_options:
self.freeform_buttons.add(x)
self.freetag = freeform_options[0]
base.balloon.bind(self.freeform_buttons,
"""If this Pyfort input file uses a C or c in column 1 as a comment,
choose that option here.
""")
self.compiler_buttons = Pmw.RadioSelect(w.interior(),
buttontype = 'radiobutton',
orient = 'horizontal',
labelpos = 'w',
command = self.compilercallback,
label_text = 'Target Language',
)
self.compiler_buttons.pack(side = 'top', anchor='w', expand = 1, fill = 'x')
for x in ['Fortran', 'C ']:
self.compiler_buttons.add(x)
self.c_compiler_tag = "Fortran"
base.balloon.bind(self.compiler_buttons,
"""Choose whether this Pyfort input file will link to Fortran or C libraries.
""")
self.sourcetext = Pmw.ScrolledText (w.interior(),
label_text="List Fortran / C Source Files Here (space delimited, wildcards ok)",
labelpos='nw',
usehullsize=1,
hull_width=300,
hull_height=100,
)
self.sourcetext.pack(side='top', expand=1, fill='x')
base.balloon.bind(self.sourcetext,r"""Compiled sources
List here, white-space delimited, the Fortran or C sources you wish to
compile into your Pyfort extension for this .pyf file.
You can use wildcards. Patterns are matched using glob.glob:
* matches everything
? matches any single character
[seq] matches any character in seq
[!seq] matches any char not in seq
An initial period is not special.
Both FILENAME and PATTERN are first case-normalized
if the operating system requires it.
You can put either C or Fortran source files here, but not both, and
you must check the appropriate 'Target Language' button. Note that Pyfort
is not a general tool for connecting to C; it expects Fortran-"like" routine
interfaces and data types.
""")
w = Pmw.Group(f1, tag_pyclass = Tkinter.Button,
tag_text = 'Show Advanced Options')
w.pack(side='top',anchor='w', fill='x', pady=5)
self.advanced_button = w.component('tag')
self.advanced_button.configure(command=self.advanced_click)
self.advanced_frame = Tkinter.Frame(w.interior())
self.advanced_frame.pack (fill='both', expand=1, side='top', anchor='w')
self.compiler_options_entry = Pmw.EntryField(self.advanced_frame,
labelpos='w',
label_text='Compiler options',
value = ''
)
base.balloon.bind(self.compiler_options_entry, """Compiler options
Put any additional options needed to compile the Fortran / C routines,
such as -I include directives, or optimization directives.
""")
self.compiler_options_entry.pack(expand=1, side='top', anchor='w', fill='x')
self.libnames_entry = Pmw.EntryField(self.advanced_frame,
labelpos='w',
label_text='External library names',
value = ''
)
self.libnames_entry.pack(expand=1, side='top', anchor='w', fill='x')
libhelp = \
"""If your Fortran or C is not self-contained, you may need to link with
additional libraries. Put a space-delimited list of those in the
'Link libraries' box and a space-delimited list of directories holding
such libraries in the 'Link directories' box. Otherwise leave them blank.
The library name is as usually specified to the linker. This is the name
without any prefixes or suffices, e.g. 'rs' for the library librs.a.
"""
base.balloon.bind(self.libnames_entry, libhelp)
self.libdirs_entry = Pmw.EntryField(self.advanced_frame,
labelpos='w',
label_text='External library directories',
value = ''
)
self.libdirs_entry.pack(expand=1, side='top', anchor='w', fill='x')
base.balloon.bind(self.libdirs_entry, libhelp)
self.python_directory_entry = Pmw.EntryField(self.advanced_frame,
labelpos='w',
label_text='Directory containing Python sources',
value = ''
)
self.python_directory_entry.pack(expand=1, side='top', anchor='w', fill='x')
base.balloon.bind(self.python_directory_entry,
"""If you have Python code as well as Fortran in your package,
put the name of the directory that holds the Python code
here. Otherwise leave it blank.
""")
self.package_name_entry = Pmw.EntryField(self.advanced_frame,
labelpos='w',
label_text='Python Package Name',
value = ''
)
self.package_name_entry.pack(side='top', anchor='w')
base.balloon.bind(self.package_name_entry,
"""Set here if desired the name of the package into which to insert the
generated extension. To do this, create a directory
which you set in the "Python Directory" box. In the directory you place
any Python files you have created to go with the pyf extension, and
a file named __init__.py (two underscores on each side); typically this
file either contains your Python code directly or imports the names
of the functions you wish to expose to the user from your other Python files.
In this case when you refer to the Fortran extension generated by the pyf
file you will use packagename.extensionname.
""")
Pmw.alignlabels([
self.generate_as_entry,
self.freeform_buttons,
self.compiler_buttons,
])
Pmw.alignlabels([
self.compiler_options_entry,
self.python_directory_entry,
self.package_name_entry,
self.libnames_entry,
self.libdirs_entry,
])
self.set_advanced (0)
self.generate_as_entry.component('entry').configure(bg='white')
self.python_directory_entry.component('entry').configure(bg='white')
self.package_name_entry.component('entry').configure(bg='white')
self.libnames_entry.component('entry').configure(bg='white')
self.libdirs_entry.component('entry').configure(bg='white')
self.compiler_options_entry.component('entry').configure(bg='white')
self.sourcetext.component('text').configure(bg='white')
def advanced_click (self):
self.set_advanced (1-self.show_advanced)
def set_advanced (self, flag):
self.show_advanced = flag
if flag:
self.advanced_button.configure(text='Hide Advanced Options')
self.advanced_frame.pack (side='top', anchor='w', fill='x')
else:
self.advanced_button.configure(text='Show Advanced Options')
self.advanced_frame.pack_forget()
def freeformcallback(self, tag):
self.freetag = tag
def compilercallback(self, tag):
self.c_compiler_tag = tag
def put (self, pyf):
self.filename = pyf.filename
self.name = pyf.name
self.g1.configure(tag_text=self.filename)
if pyf.freeform:
self.freeform_buttons.invoke(0)
else:
self.freeform_buttons.invoke(1)
if pyf.use_c_compiler:
self.compiler_buttons.invoke(1)
else:
self.compiler_buttons.invoke(0)
self.generate_as_entry.setentry(pyf.generated_module_name())
self.python_directory_entry.setentry(pyf.python_directory)
self.package_name_entry.setentry(pyf.package_name)
self.compiler_options_entry.setentry(pyf.compiler_options)
self.libnames_entry.setentry(pyf.libraries)
self.libdirs_entry.setentry(pyf.library_directories)
for x in pyf.sources:
self.sourcetext.insert('end', x)
self.sourcetext.insert('end','\n')
self.set_advanced(pyf.is_advanced())
def get (self):
if not self.filename:
return None
pyf = project.pyf(self.filename)
x = self.python_directory_entry.component('entry').get()
pyf.python_directory = x
x = self.package_name_entry.component('entry').get()
pyf.package_name = x
x = self.libnames_entry.component('entry').get()
pyf.libraries = x
x = self.libdirs_entry.component('entry').get()
pyf.library_directories = x
x = self.compiler_options_entry.component('entry').get()
pyf.compiler_options = x
x = self.generate_as_entry.component('entry').get()
if x != pyf.name:
pyf.generate_as = x
if self.freetag == freeform_options[0]:
pyf.freeform = 1
else:
pyf.freeform = 0
if self.c_compiler_tag == "Fortran":
pyf.use_c_compiler = 0
else:
pyf.use_c_compiler = 1
text = self.sourcetext.get()
pyf.sources = text.split()
return pyf
|