# -*- 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('', self.ok) self.bind('', 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('', 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('', 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 event. """ self.bind("", 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("<>", "", "", "") self.cbx.entry.bind("<>", 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 #-------------------------------------------------------------------------------