# -*- coding: iso-8859-1 -*-
#
#-------------------------------------------------------------------------------
# Code_Saturne version 1.3
# ------------------------
#
#
# This file is part of the Code_Saturne User Interface, element of the
# Code_Saturne CFD tool.
#
# Copyright (C) 1998-2007 EDF S.A., France
#
# contact: saturne-support@edf.fr
#
# The Code_Saturne User Interface is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# The Code_Saturne User Interface is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with the Code_Saturne Kernel; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor,
# Boston, MA 02110-1301 USA
#
#-------------------------------------------------------------------------------
"""
This module defines the window dialog classes for the Tk GUI.
This module defines the following classes:
- Dialog
- ShowInfo
- About
- Warning
- Error
- AskYesNo (to be used with the askyesno function)
- DirSelect (to be used with the dirselect function)
- DialogText
"""
#-------------------------------------------------------------------------------
# Library modules import
#-------------------------------------------------------------------------------
import os
import Tix
from Tkconstants import *
#-------------------------------------------------------------------------------
# Application modules import
#-------------------------------------------------------------------------------
from Common import *
import Toolbox
import TkPage
#-------------------------------------------------------------------------------
# Popup dialog Windows
#-------------------------------------------------------------------------------
class Dialog(Tix.Toplevel):
"""
Class to open dialogs.
This class is intended as a base class for custom dialogs.
This class is a mix from SimpleDialog.py and Dialog.py (with little changes)
"""
def __init__(self, parent=None, **options):
"""
Initialize a dialog popup window.
Arguments:
parent -- a parent window (the application window)
options['parent'] -- idem
options['title'] -- the dialog title
options['default'] -- object which contains parameters
options['stbar'] -- status bar for status message and balloon widget
options['case'] -- object which contens the current case
options['class_'] -- new widget class name
"""
for key in options.keys():
if key not in ('parent','title','default','stbar','case','class_'):
raise TypeError, "__init__() got an unexpected keyword argument '%s'"%key
if not parent and options.has_key('parent'):
parent = options['parent']
if not parent:
raise TypeError, "__init__() takes at least 2 non-keyword argument (1 given)"
if options.has_key('class_'):
Tix.Toplevel.__init__(parent, class_=options['class_'])
else:
Tix.Toplevel.__init__(self, parent)
if options.has_key('title'):
self.title(options['title'])
self.iconname(options['title'])
self.parent = parent
self.check2 = TkPage.DataValidator2()
# Fonts.
#
Toolbox.setupFontDefault(self)
# Look for the status bar and the balloon widget
#
if options.has_key('stbar'):
self.stbar = options['stbar']
self.balloon = Tix.Balloon(self, statusbar=self.stbar.label, bd=1, bg='black')
self.balloon.message.config(bg=wm['background'])
# Attribute for results storage
#
self.result = None
# Attribute for Dialog Window configuration
#
if options.has_key('default'):
self.default = options['default']
# Current case
#
if options.has_key('case'):
self.case = options['case']
self.protocol('WM_DELETE_WINDOW', self.cancel)
frame = Tix.Frame(self, relief=FLAT)
frame.pack()
self.initial_focus = self.body(frame)
if not self.initial_focus:
self.initial_focus = self
self.sequence()
self.buttonbox()
# Call this function AFTER the layout of all children widgets
#
self._set_transient(parent)
# Make sure that no mouse or keyboard events are sent to the wrong window
#
self.grab_set()
# Move the keyboard focus to the dialog window
#
self.initial_focus.focus_set()
# Start local event lopp, and resume execusion of parent window
#
self.wait_window(self)
def _set_transient(self, parent, relx=0.5, rely=0.3):
"""
Manage the display of new window.
"""
# Remain invisible while we figure out the geometry
#
self.withdraw()
# A transient window is allways drawn on top of its parent
#
self.transient(parent)
# Actualize geometry information
#
self.update_idletasks()
if parent.winfo_ismapped():
m_width = parent.winfo_width()
m_height = parent.winfo_height()
m_x = parent.winfo_rootx()
m_y = parent.winfo_rooty()
else:
m_width = parent.winfo_screenwidth()
m_height = parent.winfo_screenheight()
m_x = m_y = 0
w_width = self.winfo_reqwidth()
w_height = self.winfo_reqheight()
x = m_x + (m_width - w_width) * relx
y = m_y + (m_height - w_height) * rely
if x+w_width > parent.winfo_screenwidth():
x = parent.winfo_screenwidth() - w_width
elif x < 0:
x = 0
if y+w_height > parent.winfo_screenheight():
y = parent.winfo_screenheight() - w_height
elif y < 0:
y = 0
self.geometry("+%d+%d" % (x, y))
# Become visible at the desired location
#
self.deiconify()
def destroy(self):
"""
Destroy the window
"""
self.initial_focus = None
Tix.Toplevel.destroy(self)
#
# construction hooks
def body(self, master):
"""
Create dialog body.
Return widget that should have initial focus.
This method should be overridden, and is called
by the __init__ method.
"""
pass
def sequence(self):
"""
Bind the dialog window with 'Echap' and 'Return'
Override if you don't want the standard binding
(for example ou have to bind the dialog window
with only 'Echap' and delete sequence 'Return',
when there is any entries on the dialog window).
"""
self.bind('<Return>', self.ok)
self.bind('<Escape>', self.cancel)
def buttonbox(self):
"""
Add standard button box.
Override if you don't want the standard buttons.
"""
t = DialogText()
# Separator
#
Tix.Frame(self, height=2, bd=2, relief=SUNKEN).pack(side=TOP, fill=X)
# Button box
#
box = Tix.Frame(self, relief=FLAT)
box.pack()
b1 = Tix.Button(box, text=t.VALIDATE,
underline=0, width=10,
command=self.ok, default=ACTIVE)
b1.grid(row=0, column=0, padx=5, pady=10)
b1.bind('<Return>', self.ok)
b2 = Tix.Button(box, text=t.CANCEL,
underline=0, width=10,
command=self.cancel)
b2.grid(row=0, column=1, padx=5, pady=10)
b2.bind('<Return>', self.cancel)
#
# standard button semantics
def ok(self, event=None):
"""
First hide the dialog window, then call the apply method, and
finally destroy the dialog window.
"""
if not self.validate():
# put focus back
#
self.initial_focus.focus_set()
return
# Put invisible and actualize geometry information
#
self.withdraw()
self.update_idletasks()
self.apply()
# put focus back to the parent window and close the dialog window.
#
self.parent.focus_set()
self.destroy()
def cancel(self, event=None):
"""
Close the dialog window.
You should override it if necessary.
"""
self.result = self.default
# put focus back to the parent window
#
self.parent.focus_set()
self.destroy()
#
# command hooks
def validate(self):
"""
This method is called automatically to validate the data before the
dialog is destroyed. By default, it always validates OK.
You should override it if necessary.
"""
return 1
def apply(self):
"""
Process the data.
This method is called automatically to process the data, *after*
the dialog is destroyed. By default, it does nothing.
You should override it.
"""
pass
#
# usefull methods
def _scrollHandler(self, entry, *L):
"""
Making an Entry widget scrollable.
Code stolen from:
New Mexico Tech Computer Center, "Tkinter reference", p28
"""
op, howMany = L[0], L[1]
if op =="scroll":
units = L[2]
entry.xview_scroll(howMany, units)
elif op == "moveto":
entry.xview_moveto(howMany)
#-------------------------------------------------------------------------------
# ShowInfo popup window
#-------------------------------------------------------------------------------
class ShowInfo(Dialog):
"""
This class is intended as a base class for Informations dialog window.
It is usefull two for the About dialog window.
"""
def __init__(self, parent=None, **options):
"""
Initialize a ShowInfo dialog popup window.
Arguments:
parent -- a parent window (the application window)
options['parent'] -- idem
options['title'] -- the dialog title
options['text'] -- object which contains the texte of the dialog popup window
options['image'] -- the image to display in the left of the window
options['justify'] -- text justification (CENTER, LEFT(default), RIGHT)
options['length'] -- number max of characters in each line
options['default'] -- object which contains parameters
"""
# Check arguments, an options[key] set to 'None' is deleted in order to take
# a default value.
#
for key in options.keys():
if key not in ('parent','title','default','text','image','length','justify'):
raise TypeError, "__init__() got an unexpected keyword argument '%s'"%key
else:
if options[key] == None: del options[key]
# Set default values
#
if not parent and options.has_key('parent'):
parent = options['parent']
if not parent:
raise TypeError, "__init__() takes at least 2 non-keyword arguments (1 given)"
if options.has_key('text'):
self.text = options['text']
else:
self.text = ""
if options.has_key('image'):
self.image = PIC_PATH + options['image']
else:
self.image = PIC_PATH + 'boussole.gif'
if options.has_key('length'):
self.lenght = options['length']
else:
self.lenght = LENGHT_WIDTH
if options.has_key('justify'):
self.justify = options['justify']
else:
self.justify = LEFT
if not options.has_key('default'):
options['default'] = "no"
if not options.has_key('title'):
options['title'] = ""
Dialog.__init__(self, parent, title=options['title'], default=options['default'])
def body(self, master):
"""
Format selector layout
"""
# Window dialog layout
#
self.img = Tix.PhotoImage(file=self.image)
w, h = self.img.width(), self.img.height()
Tix.Label(master, width=w, height=h,
relief=SUNKEN, bd=1, image=self.img) \
.pack(side=LEFT, padx=15, pady=15, ipadx=5, ipady=5)
Tix.Label(master, text=self.text,
relief=FLAT, wraplength=self.lenght, justify=self.justify) \
.pack(side=LEFT, padx=20, pady=20)
def buttonbox(self):
"""
Override standard button box.
"""
t = DialogText()
# Separator
#
Tix.Frame(self, height=2, bd=2, relief=SUNKEN).pack(side=TOP, fill=X)
# Button box
#
box = Tix.Frame(self, relief=FLAT)
box.pack()
b = Tix.Button(box, text=t.CLOSE, underline=0, width=10,
command=self.cancel, default=ACTIVE)
b.pack(side=TOP, padx=10, pady=10)
#-------------------------------------------------------------------------------
# About popup window
#-------------------------------------------------------------------------------
class About(ShowInfo):
"""
Initialize an About dialog popup window.
"""
def __init__(self, parent,
title=None, text=None, image=None,
justify=None, length=None):
"""
Arguments:
parent -- a parent window (the application window)
title -- the dialog title
text -- object which contains the texte of the dialog popup window
image -- the image to display in the left of the window
justify -- text justification (CENTER (default), LEFT, RIGHT)
length -- number max of characters in each line
"""
t = DialogText()
if not title:
title = t.ABOUT
if not text:
text = t.MSG_ABOUT
if not image:
image = 'telephone.gif'
if not justify:
justify = CENTER
if not length:
length = 250
ShowInfo.__init__(self, parent, title=title, text=text,
image=image, justify=justify, length=length)
#-------------------------------------------------------------------------------
# Warning popup window
#-------------------------------------------------------------------------------
class Warning(ShowInfo):
"""
Initialize a Warning dialog popup window.
"""
def __init__(self, parent,
title=None, text=None, image=None,
justify=None, length=None):
"""
Arguments:
parent -- a parent window (the application window)
title -- the dialog title
text -- object which contains the texte of the dialog popup window
image -- the image to display in the left of the window
justify -- text justification (CENTER, LEFT(default), RIGHT)
length -- number max of characters in each line
"""
if not title:
t = DialogText()
title = t.WARNING
if not image:
image = 'danger.gif'
ShowInfo.__init__(self, parent, title=title, text=text,
image=image, justify=justify, length=length)
#-------------------------------------------------------------------------------
# Error popup window
#-------------------------------------------------------------------------------
class Error(ShowInfo):
"""
Initialize an Error dialog popup window.
"""
def __init__(self, parent,
title=None, text=None, image=None,
justify=None, length=None):
"""
Arguments:
parent -- a parent window (the application window)
title -- the dialog title
text -- object which contains the texte of the dialog popup window
image -- the image to display in the left of the window
justify -- text justification (CENTER, LEFT(default), RIGHT)
length -- number max of characters in each line
"""
if not title:
t = DialogText()
title = t.ERROR
if not image:
image = 'tete_de_mort.gif'
ShowInfo.__init__(self, parent, title=title, text=text,
image=image, justify=justify, length=length)
#-------------------------------------------------------------------------------
# AskYesNo popup window
#-------------------------------------------------------------------------------
class AskYesNo(ShowInfo):
"""
Initialize an AskYesNo dialog popup window.
"""
def __init__(self, parent,
title=None, text=None, image=None,
justify=None, length=None, default='no'):
"""
Arguments:
parent -- a parent window (the application window)
title -- the dialog title
text -- object which contains the texte of the dialog popup window
image -- the image to display in the left of the window
justify -- text justification (CENTER (default), LEFT, RIGHT)
length -- number max of characters in each line
default -- object which contains parameters
"""
if not title:
t = DialogText()
title = t.QUESTION
if not image:
image = 'question.gif'
ShowInfo.__init__(self, parent, title=title, text=text, image=image,
justify=justify, length=length, default=default)
def buttonbox(self):
"""
Override standard button box.
"""
t = DialogText()
# Separator
#
Tix.Frame(self, height=2, bd=2, relief=SUNKEN).pack(side=TOP, fill=X)
# Button box
#
box = Tix.Frame(self, relief=FLAT)
box.pack()
b1 = Tix.Button(box, text=t.YES,
underline=0, width=10,
command=self.ok, default=ACTIVE)
b1.grid(row=0, column=0, padx=10, pady=10)
b2 = Tix.Button(box, text=t.NO,
underline=0, width=10,
command=self.cancel)
b2.grid(row=0, column=1, padx=10, pady=10)
def apply(self):
"""
What to do when user clicks on 'YES'.
"""
self.result = 'yes'
def askyesno (parent, **options):
"""
Ask a question, and return the answer
"""
return AskYesNo(parent, **options).result
#-------------------------------------------------------------------------------
# DirSelect popup window
#-------------------------------------------------------------------------------
class DirSelect(Dialog):
"""
Initialize a directory selector dialog popup window.
"""
def __init__(self, parent=None, **options):
"""
Arguments:
parent -- a parent window (the application window)
options['parent'] -- idem
options['title'] -- the dialog title
options['stbar'] -- status bar for status message and balloon widget
options['image'] -- the image to display in the left of the window
options['default'] -- object which contains parameters
"""
# Check arguments, an options[key] set to 'None' is deleted in order to take
# a default value.
#
for key in options.keys():
if key not in ('parent','title','default','image', 'stbar'):
raise TypeError, "__init__() got an unexpected keyword argument '%s'"%key
else:
if options[key] == None: del options[key]
# Set default values
#
if not parent and options.has_key('parent'):
parent = options['parent']
if not parent:
raise TypeError, "__init__() takes at least 2 non-keyword arguments (1 given)"
if options.has_key('image'):
self.image = PIC_PATH + options['image']
else:
self.image = PIC_PATH + 'file_cabinet.gif'
if not options.has_key('default'):
options['default'] = '/home'
if not options.has_key('title'):
t = DialogText()
options['title'] = t.DIRECTORY
Dialog.__init__(self, parent, title=options['title'],
default=options['default'], stbar=options['stbar'])
def sequence(self):
"""
Bind the dialog window only with 'Echap'.
Override the generic sequence method because the ComboBox is binded
with the <Return> event.
"""
self.bind("<Escape>", self.cancel)
def selectTreeDir(self, pathName):
"""
When the user click (or bouble-click) on a folder, its name is put in the
ComboBox entry.
"""
try:
if os.path.isdir(pathName):
self.cbx_dir.set(pathName)
self._scrollHandler(self.cbx.entry, "moveto", 1)
self.tree.hlist.xview(pathName)
except TypeError:
pass
def changeDirInTree(self, dir):
"""
Update the Tree with a new directory.
"""
self.tree.chdir(dir)
# the following try/except syntaxe is used because of a Tix bug.
# We have a trouble shooting when self.default=os.getcwd() .
#
try:
self.tree.hlist.selection_clear()
self.tree.hlist.selection_set(dir)
except:
pass
def selectCbxDir(self, event=None):
"""
- verify that the input directory exist
- add the directory in the slistbox
- update the DirTree with this new directory
"""
try:
dir = self.cbx_dir.get()
if os.path.isdir(dir):
self.cbx.add_history(dir)
self.check2.begin(self.cbx.entry)
self.changeDirInTree(dir)
else:
self.check2.error(self.cbx.entry)
t = DialogText()
except TypeError:
self.check2.error(self.cbx.entry)
# These 2 lines actually does not work
#
self.cbx.entry.selection_range(0,0)
self._scrollHandler(self.cbx.entry, "moveto", 1)
def showHiddenFolders(self, event=None):
"""
Specifies whether hidden directories should be shown.
"""
if self.hiddenFolders.get() == 'on':
self.tree.config(showhidden="1")
else:
self.tree.config(showhidden="0")
def body(self, master):
"""
Format selector layout
"""
t = DialogText()
# Tkinter variables declaration
#
self.cbx_dir = Tix.StringVar()
self.hiddenFolders = Tix.StringVar()
# Image layout
#
self.img = Tix.PhotoImage(file=self.image)
w, h = self.img.width(), self.img.height()
Tix.Label(master, width=w, height=h,
relief=SUNKEN, bd=1, image=self.img) \
.pack(side=LEFT, padx=15, pady=15, ipadx=5, ipady=5)
# Frame and title layout
#
top = Tix.Frame(master, relief=FLAT)
top.pack(side=LEFT, padx=20, pady=20)
frame1 = Tix.Frame(top, relief=FLAT)
frame1.pack(side=TOP)
Tix.Label(frame1, text= t.DIRECTORY, relief=FLAT).\
pack(side=TOP, anchor=W, padx=6, pady=2)
# ComboBox layout
#
self.cbx = Tix.ComboBox(frame1,
editable=1,
history=0,
historylimit=20,
bd=2,
listwidth=210,
selectmode="",
variable=self.cbx_dir)
self.cbx.entry.event_add("<<E>>", "<Return>", "<Leave>", "<FocusOut>")
self.cbx.entry.bind("<<E>>", self.selectCbxDir)
self.cbx.slistbox.config(height=100, scrollbar="auto")
self.cbx.slistbox.vsb.config(width=10, bd=1)
self.cbx.slistbox.hsb.config(width=10, bd=1)
self.cbx.pack(side=TOP, anchor=W, fill=X)
self.cbx.config(command=self.selectCbxDir)
# Scrollbar layout
#
self.scrollcbx = Tix.Scrollbar(frame1, orient=HORIZONTAL, width=10, bd=1,
command=TkPage.Callback(self._scrollHandler,\
self.cbx.entry))
self.scrollcbx.pack(side=TOP, fill=X, anchor=W, padx=6, pady=0)
self.cbx.entry['xscrollcommand'] = self.scrollcbx.set
# DirTree layout
#
self.tree = Tix.DirTree(top, options=' hlist.wideSelection "1" \
hlist.wideSelection "1" \
hlist.selectmode "single" ' )
self.tree.config(width=200, height=300, browsecmd=self.selectTreeDir)
self.tree.hlist.config(background=wm['treebackground'],
selectbackground=wm['treeselectcolor'])
self.tree.vsb.config(width=10, bd=1)
self.tree.hsb.config(width=10, bd=1)
self.tree.pack(side=TOP, expand=1, fill=BOTH, pady=10)
# Show hidden folders
#
frame2 = Tix.Frame(top, relief=FLAT)
frame2.pack(side=TOP)
l = Tix.Label(frame2, text=t.HIDDEN_FOLDERS)
l.grid(row=1, column=0, padx=5, pady=0, sticky=W)
c = Tix.Checkbutton(frame2, onvalue='on', offvalue='off',
variable=self.hiddenFolders,
command=self.showHiddenFolders)
c.grid(row=1, column=1, sticky=E)
# Default Value
#
self.changeDirInTree(self.default)
# the following try/except syntaxe is used because of a Tix bug.
# We have a trouble shooting when self.default=os.getcwd() .
#
try:
self.tree.hlist.yview(self.default)
except:
pass
self.cbx_dir.set(self.default)
self.cbx.append_history(self.default)
self._scrollHandler(self.cbx.entry, "moveto", 1)
c.deselect()
# Must we change the returned default directory?
#
self.default = None
def apply(self):
"""
What to do when user clicks on 'YES'.
"""
self.result = self.cbx_dir.get()
def dirselect (parent, **options):
"""
Ask for a directory, and return its name
"""
return DirSelect(parent, **options).result
#-------------------------------------------------------------------------------
# Texts for this module
#-------------------------------------------------------------------------------
class DialogText:
"""
Storage of all texts and messages for this module.
"""
def __init__(self):
# 1) Texts
#
if Toolbox.GuiParam.lang == 'fr':
self.ABOUT = "À propos"
self.CANCEL = "Annuler"
self.CLOSE = "Fermer"
self.DIRECTORY = "Répertoire :"
self.ERROR = "Erreur"
self.HIDDEN_FOLDERS = "Afficher les répertoires cachés"
self.QUESTION = "Question"
self.NO = "Non"
self.VALIDATE = "Valider"
self.WARNING = "Attention"
self.YES = "Oui"
else:
self.ABOUT = "About"
self.CANCEL = "Cancel"
self.CLOSE = "Close"
self.DIRECTORY = "Directory:"
self.ERROR = "Error"
self.HIDDEN_FOLDERS = "Show hidden directories"
self.QUESTION = "Question"
self.NO = "No"
self.VALIDATE = "Validate"
self.WARNING = "Warning"
self.YES = "Yes"
# 2) Messages
#
if Toolbox.GuiParam.lang == 'fr':
self.MSG_ABOUT = "Interface Code_Saturne\n" +\
"version " + VERSION + "\n\n" +\
"Pour toutes informations à propos de cette " +\
"application merci de contacter :\n\n" +\
"Alexandre Douce\n" +\
"(0130877308 - Alexandre.Douce@edf.fr)\n\n" +\
"Nicole Picard\n" +\
"(0130877824 - Nicole-N.Picard@edf.fr)\n\n" +\
"Jean-Luc Rousset\n" +\
"(0130877943 - Jean-Luc.Rousset@edf.fr)"
else:
self.MSG_ABOUT = "Code_Saturne Interface\n" +\
"version " + VERSION + "\n\n" +\
"For information about this application " +\
"please contact :\n\n" +\
"Alexandre Douce\n" +\
"(0130877308 - Alexandre.Douce@edf.fr)\n\n" +\
"Nicole Picard\n" +\
"(0130877824 - Nicole-N.Picard@edf.fr)\n\n" +\
"Jean-Luc Rousset\n" +\
"(0130877943 - Jean-Luc.Rousset@edf.fr)"
#-------------------------------------------------------------------------------
# End of Dialog
#-------------------------------------------------------------------------------
syntax highlighted by Code2HTML, v. 0.9.1