home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyos2bin.zip / Demo / stdwin / miniedit.py < prev    next >
Text File  |  1996-11-27  |  9KB  |  357 lines

  1. #! /usr/bin/env python
  2.  
  3. # A miniature multi-window editor using STDWIN's text objects.
  4. #
  5. # Usage: miniedit [file] ...
  6. #
  7. # The user interface is similar to that of the miniedit demo application
  8. # in C that comes with STDWIN.
  9. #
  10. # XXX need to comment the functions
  11. # XXX Not yet implemented:
  12. #    disabling menu entries for inapplicable actions
  13. #    Find operations
  14.  
  15.  
  16. import sys
  17. import stdwin
  18. from stdwinevents import *
  19.  
  20.  
  21. # Constant: list of WE_COMMAND events that (may) change the text buffer
  22. # so we can decide whether to set the 'changed' flag.
  23. # Note that it is possible for such a command to fail (a backspace
  24. # at the beginning of the buffer) but we'll set the changed flag anyway
  25. # -- it's too complicated to check this condition right now.
  26. #
  27. changing = [WC_RETURN, WC_TAB, WC_BACKSPACE]
  28.  
  29.  
  30. # The list of currently open windows;
  31. # this is maintained so we can stop when there are no windows left
  32. #
  33. windows = []
  34.  
  35.  
  36. # A note on window data attributes (set by open_window):
  37. #
  38. # w.textobject    the window's text object
  39. # w.changed    true when the window's text is changed
  40. # w.filename    filename connected to the window; '' if none
  41.  
  42.  
  43. # Main program
  44. #
  45. def main():
  46.     #
  47.     # Set a reasonable default window size.
  48.     # If we are using a fixed-width font this will open a 80x24 window;
  49.     # for variable-width fonts we approximate this based on an average
  50.     #
  51.     stdwin.setdefwinsize(40*stdwin.textwidth('in'), 24*stdwin.lineheight())
  52.     #
  53.     # Create global menus (as local variables)
  54.     #
  55.     filemenu = make_file_menu(stdwin)
  56.     editmenu = make_edit_menu(stdwin)
  57.     findmenu = make_find_menu(stdwin)
  58.     #
  59.     # Get the list of files from the command line (maybe none)
  60.     #
  61.     files = sys.argv[1:]
  62.     #
  63.     # Open any files -- errors will be reported but do won't stop us
  64.     #
  65.     for filename in files:
  66.         open_file(filename)
  67.     #
  68.     # If there were no files, or none of them could be opened,
  69.     # put up a dialog asking for a filename
  70.     #
  71.     if not windows:
  72.         try:
  73.             open_dialog(None)
  74.         except KeyboardInterrupt:
  75.             pass        # User cancelled
  76.     #
  77.     # If the dialog was cancelled, create an empty new window
  78.     #
  79.     if not windows:
  80.         new_window(None)
  81.     #
  82.     # Main event loop -- stop when we have no open windows left
  83.     #
  84.     while windows:
  85.         #
  86.         # Get the next event -- ignore interrupts
  87.         #
  88.         try:
  89.             type, window, detail = event = stdwin.getevent()
  90.         except KeyboardInterrupt:
  91.             type, window, detail = event = WE_NONE, None, None
  92.         #
  93.         # Event decoding switch
  94.         #
  95.         if not window:
  96.             pass        # Ignore such events
  97.         elif type == WE_MENU:
  98.             #
  99.             # Execute menu operation
  100.             #
  101.             menu, item = detail
  102.             try:
  103.                 menu.actions[item](window)
  104.             except KeyboardInterrupt:
  105.                 pass    # User cancelled
  106.         elif type == WE_CLOSE:
  107.             #
  108.             # Close a window
  109.             #
  110.             try:
  111.                 close_dialog(window)
  112.             except KeyboardInterrupt:
  113.                 pass    # User cancelled
  114.         elif type == WE_SIZE:
  115.             #
  116.             # A window was resized --
  117.             # let the text object recompute the line breaks
  118.             # and change the document size accordingly,
  119.             # so scroll bars will work
  120.             #
  121.             fix_textsize(window)
  122.         elif window.textobject.event(event):
  123.             #
  124.             # The event was eaten by the text object --
  125.             # set the changed flag if not already set
  126.             #
  127.             if type == WE_CHAR or \
  128.                type == WE_COMMAND and detail in changing:
  129.                 window.changed = 1
  130.                 fix_docsize(window)
  131.         #
  132.         # Delete all objects that may still reference the window
  133.         # in the event -- this is needed otherwise the window
  134.         # won't actually be closed and may receive further
  135.         # events, which will confuse the event decoder
  136.         #
  137.         del type, window, detail, event
  138.  
  139.  
  140. def make_file_menu(object):
  141.     menu = object.menucreate('File')
  142.     menu.actions = []
  143.     additem(menu, 'New',        'N', new_window)
  144.     additem(menu, 'Open..',        'O', open_dialog)
  145.     additem(menu, '',        '',  None)
  146.     additem(menu, 'Save',        'S', save_dialog)
  147.     additem(menu, 'Save As..',    '',  save_as_dialog)
  148.     additem(menu, 'Save a Copy..',    '',  save_copy_dialog)
  149.     additem(menu, 'Revert',        'R', revert_dialog)
  150.     additem(menu, 'Quit',        'Q', quit_dialog)
  151.     return menu
  152.  
  153.  
  154. def make_edit_menu(object):
  155.     menu = object.menucreate('Edit')
  156.     menu.actions = []
  157.     additem(menu, 'Cut',        'X', do_cut)
  158.     additem(menu, 'Copy',        'C', do_copy)
  159.     additem(menu, 'Paste',        'V', do_paste)
  160.     additem(menu, 'Clear',        'B', do_clear)
  161.     additem(menu, 'Select All',    'A', do_select_all)
  162.     return menu
  163.  
  164.  
  165. def make_find_menu(object):
  166.     menu = object.menucreate('Find')
  167.     menu.actions = []
  168.     # XXX
  169.     return menu
  170.  
  171.  
  172. def additem(menu, text, shortcut, function):
  173.     if shortcut:
  174.         menu.additem(text, shortcut)
  175.     else:
  176.         menu.additem(text)
  177.     menu.actions.append(function)
  178.  
  179.  
  180. def open_dialog(current_ignored):
  181.     filename = stdwin.askfile('Open file:', '', 0)
  182.     open_file(filename)
  183.  
  184.  
  185. def open_file(filename):
  186.     try:
  187.         fp = open(filename, 'r')
  188.     except RuntimeError:
  189.         stdwin.message(filename + ': cannot open')
  190.         return            # Error, forget it
  191.     try:
  192.         contents = fp.read()
  193.     except RuntimeError:
  194.         stdwin.message(filename + ': read error')
  195.         return            # Error, forget it
  196.     del fp                # Close the file
  197.     open_window(filename, filename, contents)
  198.  
  199.  
  200. def new_window(current_ignored):
  201.     open_window('', 'Untitled', '')
  202.  
  203.  
  204. def open_window(filename, title, contents):
  205.     try:
  206.         window = stdwin.open(title)
  207.     except RuntimeError:
  208.         stdwin.message('cannot open new window')
  209.         return            # Error, forget it
  210.     window.textobject = window.textcreate((0, 0), window.getwinsize())
  211.     window.textobject.settext(contents)
  212.     window.changed = 0
  213.     window.filename = filename
  214.     fix_textsize(window)
  215.     windows.append(window)
  216.  
  217.  
  218. def quit_dialog(window):
  219.     for window in windows[:]:
  220.         close_dialog(window)
  221.  
  222.  
  223. def close_dialog(window):
  224.     if window.changed:
  225.         prompt = 'Save changes to ' + window.gettitle() + ' ?'
  226.         if stdwin.askync(prompt, 1):
  227.             save_dialog(window)
  228.             if window.changed:
  229.                 return    # Save failed (not) cancelled
  230.     windows.remove(window)
  231.     del window.textobject
  232.  
  233.  
  234. def save_dialog(window):
  235.     if not window.filename:
  236.         save_as_dialog(window)
  237.         return
  238.     if save_file(window, window.filename):
  239.         window.changed = 0
  240.  
  241.  
  242. def save_as_dialog(window):
  243.     prompt = 'Save ' + window.gettitle() + ' as:'
  244.     filename = stdwin.askfile(prompt, window.filename, 1)
  245.     if save_file(window, filename):
  246.         window.filename = filename
  247.         window.settitle(filename)
  248.         window.changed = 0
  249.  
  250.  
  251. def save_copy_dialog(window):
  252.     prompt = 'Save a copy of ' + window.gettitle() + ' as:'
  253.     filename = stdwin.askfile(prompt, window.filename, 1)
  254.     void = save_file(window, filename)
  255.  
  256.  
  257. def save_file(window, filename):
  258.     try:
  259.         fp = open(filename, 'w')
  260.     except RuntimeError:
  261.         stdwin.message(filename + ': cannot create')
  262.         return 0
  263.     contents = window.textobject.gettext()
  264.     try:
  265.         fp.write(contents)
  266.     except RuntimeError:
  267.         stdwin.message(filename + ': write error')
  268.         return 0
  269.     return 1
  270.  
  271.  
  272. def revert_dialog(window):
  273.     if not window.filename:
  274.         stdwin.message('This window has no file to revert from')
  275.         return
  276.     if window.changed:
  277.         prompt = 'Really read ' + window.filename + ' back from file?'
  278.         if not stdwin.askync(prompt, 1):
  279.             return
  280.     try:
  281.         fp = open(window.filename, 'r')
  282.     except RuntimeError:
  283.         stdwin.message(filename + ': cannot open')
  284.         return
  285.     contents = fp.read()
  286.     del fp                # Close the file
  287.     window.textobject.settext(contents)
  288.     window.changed = 0
  289.     fix_docsize(window)
  290.  
  291.  
  292. def fix_textsize(window):
  293.     corner = window.getwinsize()
  294.     area = (0, 0), (corner)
  295.     window.textobject.move(area)
  296.     fix_docsize(window)
  297.  
  298.  
  299. def fix_docsize(window):
  300.     area = window.textobject.getrect()
  301.     origin, corner = area
  302.     width, height = corner
  303.     window.setdocsize(0, height)
  304.  
  305.  
  306. def do_cut(window):
  307.     selection = window.textobject.getfocustext()
  308.     if not selection:
  309.         stdwin.fleep()        # Nothing to cut
  310.     elif not window.setselection(WS_PRIMARY, selection):
  311.         stdwin.fleep()        # Window manager glitch...
  312.     else:
  313.         stdwin.rotatecutbuffers(1)
  314.         stdwin.setcutbuffer(0, selection)
  315.         window.textobject.replace('')
  316.         window.changed = 1
  317.         fix_docsize(window)
  318.  
  319.  
  320. def do_copy(window):
  321.     selection = window.textobject.getfocustext()
  322.     if not selection:
  323.         stdwin.fleep()        # Nothing to cut
  324.     elif not window.setselection(WS_PRIMARY, selection):
  325.         stdwin.fleep()        # Window manager glitch...
  326.     else:
  327.         stdwin.rotatecutbuffers(1)
  328.         stdwin.setcutbuffer(0, selection)
  329.  
  330.  
  331. def do_paste(window):
  332.     selection = stdwin.getselection(WS_PRIMARY)
  333.     if not selection:
  334.         selection = stdwin.getcutbuffer(0)
  335.     if not selection:
  336.         stdwin.fleep()        # Nothing to paste
  337.     else:
  338.         window.textobject.replace(selection)
  339.         window.changed = 1
  340.         fix_docsize(window)
  341.  
  342. def do_clear(window):
  343.     first, last = window.textobject.getfocus()
  344.     if first == last:
  345.         stdwin.fleep()        # Nothing to clear
  346.     else:
  347.         window.textobject.replace('')
  348.         window.changed = 1
  349.         fix_docsize(window)
  350.  
  351.  
  352. def do_select_all(window):
  353.     window.textobject.setfocus(0, 0x7fffffff) # XXX Smaller on the Mac!
  354.  
  355.  
  356. main()
  357.