summaryrefslogtreecommitdiff
path: root/uitools/TkDlgWrapper.py
diff options
context:
space:
mode:
Diffstat (limited to 'uitools/TkDlgWrapper.py')
-rw-r--r--uitools/TkDlgWrapper.py268
1 files changed, 268 insertions, 0 deletions
diff --git a/uitools/TkDlgWrapper.py b/uitools/TkDlgWrapper.py
new file mode 100644
index 0000000..54b2236
--- /dev/null
+++ b/uitools/TkDlgWrapper.py
@@ -0,0 +1,268 @@
+#!/usr/bin/env python
+######################################################################
+# Try to access some of the newer Tk dialogs.
+# This module is inspired by the Python 1.[34] Dialog.py module.
+#
+# Mitch Chapman
+#---------------------------------------------------------------------
+# $Log: TkDlgWrapper.py,v $
+# Revision 1.1 1996/12/01 22:58:54 mchapman
+# Initial revision
+#
+######################################################################
+
+__version__ = "$Revision: 1.1 $"
+
+import Tkinter; Tk=Tkinter
+import os, copy
+
+VersionError = "VersionError"
+
+if Tk.TkVersion < 4.2:
+ raise VersionError, "This module requires Tk 4.2 or greater."
+
+######################################################################
+# This is an abstract wrapper for all classes of built-in Tk dialogs.
+# It's subclassed from Tk.Widget to gain access to widget
+# configuration methods.
+######################################################################
+class T(Tk.Widget):
+ ##################################################################
+ # Initialize a new instance.
+ ##################################################################
+ def __init__(self, widgetName, master=None, **kw):
+ self.widgetName = "__%s__" % widgetName
+ # The unadorned widgetName is the Tk command/proc which
+ # displays the dialog, e.g. tk_chooseColor
+ self.tkCommand = widgetName
+ self.master = master
+ # Defer the actual widget initialization. I want instances
+ # of T to persist even when they are not visible. For
+ # example, this allows a file selection dialog to remember
+ # what file extension it last selected. But in order to allow
+ # persistence, the creation of the underlying Tk dialog must
+ # be delayed.
+
+ # Make a copy of the configuration, so it can persist. This
+ # is where self remembers things such as the last file type
+ # selected, last color used, etc.
+ self.kw = copy.copy(kw)
+
+ ##################################################################
+ # Show the dialog.
+ ##################################################################
+ def show(self, **kw):
+ # Use the configuration options to override the current config --
+ # and remember them for later.
+ for k, v in kw.items():
+ self.kw[k] = v
+ Tk.Widget._setup(self, self.master, self.kw)
+ resultStr = apply(self.tk.call, (self.tkCommand,) +
+ self._options(self.kw))
+ try:
+ # Don't leak Python widget descriptors?
+ Tk.Widget.destroy(self)
+ except Tk.TclError: pass
+
+ return resultStr
+
+ ##################################################################
+ # Explicitly destroy a widget instance. Nothing to do, here,
+ # because the widget is gone as soon as show() returns.
+ ##################################################################
+ def destroy(self):
+ pass
+
+
+######################################################################
+# Abstract wrapper for the Tk 4.2 tk_get\(Open\|Save\)File dialog.
+# Tries to remember the last-used directory, so it can be used as
+# the initial directory next time the dialog is displayed.
+######################################################################
+class OpenSaveFile(T):
+ ##################################################################
+ # Initialize a new instance. whichDlg tells whether this is
+ # a tk_getOpenFile or a tk_getSaveFile, etc.
+ ##################################################################
+ def __init__(self, whichDlg, master=None, **kw):
+ apply(T.__init__, (self, whichDlg, master), kw)
+ self.filename = None
+
+ ##################################################################
+ # Show the dialog and return either the selected file or "".
+ ##################################################################
+ def show(self, **kw):
+ self.filename = apply(T.show, (self,), kw)
+ # Try to remember a few configuration items for the next time
+ # the dialog is displayed.
+ if self.filename:
+ dirname, basename = os.path.split(self.filename)
+
+ # Next time, start in the directory we ended in this time.
+ self.kw['initialdir'] = dirname
+
+ # Try to figure out what extension to use next time.
+ ext = os.path.splitext(basename)[1]
+ self.kw['defaultextension'] = "%s" % ext
+
+ # Try to specify the default name to use next time.
+ self.kw['initialfile'] = basename
+
+ # The Tk dialogs are a little stupid: Even if you specify
+ # an initial file with extension ".txt", the dialog will show
+ # only files matching the first set of extensions in the
+ # -filetypes option.
+ # My cheap workaround is to create a new first entry for
+ # -filetypes which matches the extension selected this
+ # time.
+ oldtypes = ()
+ if self.kw.has_key('filetypes'):
+ oldtypes = self.kw['filetypes']
+ # The following works only for Unix (and maybe Windows).
+ # Somebody wanna fix this for handling Mac file types?
+ newtypes = ()
+ dfltExt = ext or "*"
+ dfltDescription = "(Last Selected)"
+ for typespec in oldtypes:
+ description, types = typespec
+ if description == dfltDescription:
+ newtypes = ((dfltDescription, dfltExt),) + oldtypes[1:]
+ break # EXIT FOR LOOP
+ else:
+ newtypes = ((dfltDescription, dfltExt),) + oldtypes
+
+ self.kw['filetypes'] = newtypes
+
+ # The Tk dialogs are a little smart: If you create both an
+ # open and a save dialog in the same application, they seem
+ # to both slave to the same working directory. Change to dir
+ # "/blah" when opening? Then when you try to save, the
+ # default displayed directory will be "/blah".
+ # This may be a bug, given what the man pages say, but
+ # I like it.
+ return self.filename
+
+######################################################################
+# Wrapper for the tk_getOpenFile dialog.
+######################################################################
+class OpenFile(OpenSaveFile):
+ def __init__(self, master=None, **kw):
+ apply(OpenSaveFile.__init__, (self, "tk_getOpenFile", master), kw)
+
+
+######################################################################
+# Wrapper for the tk_getSaveFile dialog.
+######################################################################
+class SaveFile(OpenSaveFile):
+ def __init__(self, master=None, **kw):
+ apply(OpenSaveFile.__init__, (self, "tk_getSaveFile", master), kw)
+
+
+######################################################################
+# Wrapper for the tk_chooseColor dialog.
+######################################################################
+class ChooseColor(T):
+ ##################################################################
+ # Initialize a new instance.
+ ##################################################################
+ def __init__(self, master=None, **kw):
+ apply(T.__init__, (self, "tk_chooseColor", master), kw)
+
+
+######################################################################
+# Wrapper for the tk_messageBox dialog.
+######################################################################
+class MessageBox(T):
+ ##################################################################
+ # Initialize a new instance.
+ ##################################################################
+ def __init__(self, master=None, defaultCfg=None, **kw):
+ cfg = Tk._cnfmerge((defaultCfg or {}, kw))
+ apply(T.__init__, (self, "tk_messageBox", master), cfg)
+
+
+######################################################################
+# These are the specific types of MessageBox dialogs provided by Tk.
+# For each of these classes, the return value of show() is a string
+# containing the label of the button which was pressed.
+#
+# Yeah, I know, these aren't particularly useful when you can roll
+# your own much more beautiful dialogs in Python. But hey! They're
+# here and they work, and they're supposed to have native look-n-feel
+# on every supported platform.
+######################################################################
+
+class AbortRetryIgnore(MessageBox):
+ def __init__(self, master=None, **kw):
+ apply(MessageBox.__init__,
+ (self, master, {'icon':'error', 'type':'abortretryignore'}), kw)
+
+class OK(MessageBox):
+ def __init__(self, master=None, **kw):
+ apply(MessageBox.__init__, (self, master, {'type':'ok'}), kw)
+
+class OKCancel(MessageBox):
+ def __init__(self, master=None, **kw):
+ apply(MessageBox.__init__, (self, master, {'type':'okcancel'}), kw)
+
+class RetryCancel(MessageBox):
+ def __init__(self, master=None, **kw):
+ apply(MessageBox.__init__,
+ (self, master, {'icon':'error', 'type':'retrycancel'}), kw)
+
+class YesNo(MessageBox):
+ def __init__(self, master=None, **kw):
+ apply(MessageBox.__init__,
+ (self, master, {'icon':'question', 'type':'yesno'}), kw)
+
+class YesNoCancel(MessageBox):
+ def __init__(self, master=None, **kw):
+ apply(MessageBox.__init__,
+ (self, master, {'icon':'question', 'type':'yesnocancel'}), kw)
+
+
+######################################################################
+# Don't wrap tk_dialog -- that's already done in Dialog.py.
+######################################################################
+
+######################################################################
+# Main function for unit testing.
+######################################################################
+def main():
+ # Demo all of the message box dialog classes:
+ for c in [AbortRetryIgnore, OK, OKCancel,
+ RetryCancel, YesNo, YesNoCancel]:
+ d = c(title=c.__name__)
+ print d.show(message="This is an instance of %s." % c.__name__)
+
+ # Demo the color chooser dialog:
+ d = ChooseColor(title="PickaKuhla", initialcolor="SlateGray")
+ color = d.show()
+ print "Selected color is", `color`
+
+ # Demo the open file dialog.
+ d = OpenFile(defaultextension=".py",
+ filetypes=(("Python", ".py"),
+ ("Emacs Lisp", ".el"),
+ ("Text", ".txt"),
+ ("All Files", "*")))
+
+ # Run multiple times to demonstrate how the dialog remembers the
+ # last working directory, file extension, etc.
+ for i in range(2):
+ filename = d.show()
+ print "Open file", `d.filename`
+
+ print 72 * "_"
+ print "Current working directory is", os.getcwd()
+ d = SaveFile(defaultextension=".py",
+ filetypes=(("Pithon [er, Python]", ".py"),
+ ("Text", ".txt"),
+ ("All Files", "*")))
+ for i in range(2):
+ filename = d.show()
+ print "Save File As", `d.filename`
+
+
+if __name__ == "__main__":
+ main()