home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 April / PCWorld_2001-04_cd.bin / Software / TemaCD / webclean / !!!python!!! / BeOpen-Python-2.0.exe / PYNCHEWIDGET.PY < prev    next >
Encoding:
Python Source  |  2000-09-28  |  10.6 KB  |  311 lines

  1. """Main Pynche (Pythonically Natural Color and Hue Editor) widget.
  2.  
  3. This window provides the basic decorations, primarily including the menubar.
  4. It is used to bring up other windows.
  5. """
  6.  
  7. import sys
  8. import os
  9. import string
  10. from Tkinter import *
  11. import tkMessageBox
  12. import tkFileDialog
  13. import ColorDB
  14.  
  15. # Milliseconds between interrupt checks
  16. KEEPALIVE_TIMER = 500
  17.  
  18.  
  19.  
  20. class PyncheWidget:
  21.     def __init__(self, version, switchboard, master=None, extrapath=[]):
  22.         self.__sb = switchboard
  23.         self.__version = version
  24.         self.__textwin = None
  25.         self.__listwin = None
  26.         self.__detailswin = None
  27.         self.__helpwin = None
  28.         self.__dialogstate = {}
  29.         modal = self.__modal = not not master
  30.         # If a master was given, we are running as a modal dialog servant to
  31.         # some other application.  We rearrange our UI in this case (there's
  32.         # no File menu and we get `Okay' and `Cancel' buttons), and we do a
  33.         # grab_set() to make ourselves modal
  34.         if modal:
  35.             self.__tkroot = tkroot = Toplevel(master, class_='Pynche')
  36.             tkroot.grab_set()
  37.             tkroot.withdraw()
  38.         else:
  39.             # Is there already a default root for Tk, say because we're
  40.             # running under Guido's IDE? :-) Two conditions say no, either the
  41.             # import fails or _default_root is None.
  42.             tkroot = None
  43.             try:
  44.                 from Tkinter import _default_root
  45.                 tkroot = self.__tkroot = _default_root
  46.             except ImportError:
  47.                 pass
  48.             if not tkroot:
  49.                 tkroot = self.__tkroot = Tk(className='Pynche')
  50.             # but this isn't our top level widget, so make it invisible
  51.             tkroot.withdraw()
  52.         # create the menubar
  53.         menubar = self.__menubar = Menu(tkroot)
  54.         #
  55.         # File menu
  56.         #
  57.         filemenu = self.__filemenu = Menu(menubar, tearoff=0)
  58.         filemenu.add_command(label='Load palette...',
  59.                              command=self.__load,
  60.                              underline=0)
  61.         if not modal:
  62.             filemenu.add_command(label='Quit',
  63.                                  command=self.__quit,
  64.                                  accelerator='Alt-Q',
  65.                                  underline=0)
  66.         #
  67.         # View menu
  68.         #
  69.         views = make_view_popups(self.__sb, self.__tkroot, extrapath)
  70.         viewmenu = Menu(menubar, tearoff=0)
  71.         for v in views:
  72.             viewmenu.add_command(label=v.menutext(),
  73.                                  command=v.popup,
  74.                                  underline=v.underline())
  75.         #
  76.         # Help menu
  77.         #
  78.         helpmenu = Menu(menubar, name='help', tearoff=0)
  79.     helpmenu.add_command(label='About Pynche...',
  80.                              command=self.__popup_about,
  81.                              underline=0)
  82.         helpmenu.add_command(label='Help...',
  83.                              command=self.__popup_usage,
  84.                              underline=0)
  85.         #
  86.         # Tie them all together
  87.         #
  88.         menubar.add_cascade(label='File',
  89.                             menu=filemenu,
  90.                             underline=0)
  91.         menubar.add_cascade(label='View',
  92.                             menu=viewmenu,
  93.                             underline=0)
  94.         menubar.add_cascade(label='Help',
  95.                             menu=helpmenu,
  96.                             underline=0)
  97.  
  98.         # now create the top level window
  99.         root = self.__root = Toplevel(tkroot, class_='Pynche', menu=menubar)
  100.         root.protocol('WM_DELETE_WINDOW',
  101.                       modal and self.__bell or self.__quit)
  102.         root.title('Pynche %s' % version)
  103.         root.iconname('Pynche')
  104.         # Only bind accelerators for the File->Quit menu item if running as a
  105.         # standalone app
  106.         if not modal:
  107.             root.bind('<Alt-q>', self.__quit)
  108.             root.bind('<Alt-Q>', self.__quit)
  109.         else:
  110.             # We're a modal dialog so we have a new row of buttons
  111.             bframe = Frame(root, borderwidth=1, relief=RAISED)
  112.             bframe.grid(row=4, column=0, columnspan=2,
  113.                         sticky='EW',
  114.                         ipady=5)
  115.             okay = Button(bframe,
  116.                           text='Okay',
  117.                           command=self.__okay)
  118.             okay.pack(side=LEFT, expand=1)
  119.             cancel = Button(bframe,
  120.                             text='Cancel',
  121.                             command=self.__cancel)
  122.             cancel.pack(side=LEFT, expand=1)
  123.  
  124.     def __quit(self, event=None):
  125.         self.__tkroot.quit()
  126.  
  127.     def __bell(self, event=None):
  128.         self.__tkroot.bell()
  129.  
  130.     def __okay(self, event=None):
  131.         self.__sb.withdraw_views()
  132.         self.__tkroot.grab_release()
  133.         self.__quit()
  134.  
  135.     def __cancel(self, event=None):
  136.         self.__sb.canceled()
  137.         self.__okay()
  138.  
  139.     def __keepalive(self):
  140.         # Exercise the Python interpreter regularly so keyboard interrupts get
  141.         # through.
  142.         self.__tkroot.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive)
  143.  
  144.     def start(self):
  145.         if not self.__modal:
  146.             self.__keepalive()
  147.         self.__tkroot.mainloop()
  148.  
  149.     def window(self):
  150.         return self.__root
  151.  
  152.     def __popup_about(self, event=None):
  153.         from Main import __version__
  154.         tkMessageBox.showinfo('About Pynche ' + __version__,
  155.                               '''\
  156. Pynche %s
  157. The PYthonically Natural
  158. Color and Hue Editor
  159.  
  160. For information
  161. contact: Barry A. Warsaw
  162. email:   bwarsaw@python.org''' % __version__)
  163.  
  164.     def __popup_usage(self, event=None):
  165.         if not self.__helpwin:
  166.             self.__helpwin = Helpwin(self.__root, self.__quit)
  167.         self.__helpwin.deiconify()
  168.  
  169.     def __load(self, event=None):
  170.         while 1:
  171.             idir, ifile = os.path.split(self.__sb.colordb().filename())
  172.             file = tkFileDialog.askopenfilename(
  173.                 filetypes=[('Text files', '*.txt'),
  174.                            ('All files', '*'),
  175.                            ],
  176.                 initialdir=idir,
  177.                 initialfile=ifile)
  178.             if not file:
  179.                 # cancel button
  180.                 return
  181.             try:
  182.                 colordb = ColorDB.get_colordb(file)
  183.             except IOError:
  184.                 tkMessageBox.showerror('Read error', '''\
  185. Could not open file for reading:
  186. %s''' % file)
  187.                 continue
  188.             if colordb is None:
  189.                 tkMessageBox.showerror('Unrecognized color file type', '''\
  190. Unrecognized color file type in file:
  191. %s''' % file)
  192.                 continue
  193.             break
  194.         self.__sb.set_colordb(colordb)
  195.  
  196.     def withdraw(self):
  197.         self.__root.withdraw()
  198.  
  199.     def deiconify(self):
  200.         self.__root.deiconify()
  201.  
  202.  
  203.  
  204. class Helpwin:
  205.     def __init__(self, master, quitfunc):
  206.         from Main import __version__, docstring
  207.         self.__root = root = Toplevel(master, class_='Pynche')
  208.         root.protocol('WM_DELETE_WINDOW', self.__withdraw)
  209.         root.title('Pynche Help Window')
  210.         root.iconname('Pynche Help Window')
  211.         root.bind('<Alt-q>', quitfunc)
  212.         root.bind('<Alt-Q>', quitfunc)
  213.         root.bind('<Alt-w>', self.__withdraw)
  214.         root.bind('<Alt-W>', self.__withdraw)
  215.  
  216.         # more elaborate help is available in the README file
  217.         readmefile = os.path.join(sys.path[0], 'README')
  218.         try:
  219.             fp = None
  220.             try:
  221.                 fp = open(readmefile)
  222.                 contents = fp.read()
  223.                 # wax the last page, it contains Emacs cruft
  224.                 i = string.rfind(contents, '\f')
  225.                 if i > 0:
  226.                     contents = string.rstrip(contents[:i])
  227.             finally:
  228.                 if fp:
  229.                     fp.close()
  230.         except IOError:
  231.             sys.stderr.write("Couldn't open Pynche's README, "
  232.                              'using docstring instead.\n')
  233.             contents = docstring()
  234.  
  235.         self.__text = text = Text(root, relief=SUNKEN,
  236.                                   width=80, height=24)
  237.         self.__text.focus_set()
  238.         text.insert(0.0, contents)
  239.         scrollbar = Scrollbar(root)
  240.         scrollbar.pack(fill=Y, side=RIGHT)
  241.         text.pack(fill=BOTH, expand=YES)
  242.         text.configure(yscrollcommand=(scrollbar, 'set'))
  243.         scrollbar.configure(command=(text, 'yview'))
  244.  
  245.     def __withdraw(self, event=None):
  246.         self.__root.withdraw()
  247.  
  248.     def deiconify(self):
  249.         self.__root.deiconify()
  250.  
  251.  
  252.  
  253. class PopupViewer:
  254.     def __init__(self, module, name, switchboard, root):
  255.         self.__m = module
  256.         self.__name = name
  257.         self.__sb = switchboard
  258.         self.__root = root
  259.         self.__menutext = module.ADDTOVIEW
  260.         # find the underline character
  261.         underline = string.find(module.ADDTOVIEW, '%')
  262.         if underline == -1:
  263.             underline = 0
  264.         else:
  265.             self.__menutext = string.replace(module.ADDTOVIEW, '%', '', 1)
  266.         self.__underline = underline
  267.         self.__window = None
  268.  
  269.     def menutext(self):
  270.         return self.__menutext
  271.  
  272.     def underline(self):
  273.         return self.__underline
  274.  
  275.     def popup(self, event=None):
  276.         if not self.__window:
  277.             # class and module must have the same name
  278.             class_ = getattr(self.__m, self.__name)
  279.             self.__window = class_(self.__sb, self.__root)
  280.             self.__sb.add_view(self.__window)
  281.         self.__window.deiconify()
  282.  
  283.     def __cmp__(self, other):
  284.         return cmp(self.__menutext, other.__menutext)
  285.  
  286.  
  287. def make_view_popups(switchboard, root, extrapath):
  288.     viewers = []
  289.     # where we are in the file system
  290.     dirs = [os.path.dirname(__file__)] + extrapath
  291.     for dir in dirs:
  292.         if dir == '':
  293.             dir = '.'
  294.         for file in os.listdir(dir):
  295.             if file[-9:] == 'Viewer.py':
  296.                 name = file[:-3]
  297.                 try:
  298.                     module = __import__(name)
  299.                 except ImportError:
  300.                     # Pynche is running from inside a package, so get the
  301.                     # module using the explicit path.
  302.                     pkg = __import__('pynche.'+name)
  303.                     module = getattr(pkg, name)
  304.                 if hasattr(module, 'ADDTOVIEW') and module.ADDTOVIEW:
  305.                     # this is an external viewer
  306.                     v = PopupViewer(module, name, switchboard, root)
  307.                     viewers.append(v)
  308.     # sort alphabetically
  309.     viewers.sort()
  310.     return viewers
  311.