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