Skip to content
Snippets Groups Projects
textedit.rb 55.4 KiB
Newer Older
#!/usr/bin/env ruby

require 'fox16'
require 'fox16/responder'
require 'fox16/undolist'
require_relative 'prefdialog'
require_relative 'helpwindow'
require_relative 'commands'

include Fox

class TextWindow < FXMainWindow

  include Responder

  MAXUNDOSIZE, KEEPUNDOSIZE = 1000000, 500000

  # Define message identifiers recognized by this class
  ID_ABOUT,
  ID_FILEFILTER,
  ID_OPEN,
  ID_OPEN_SELECTED,
  ID_REOPEN,
  ID_SAVE,
  ID_SAVEAS,
  ID_NEW,
  ID_TITLE,
  ID_FONT,
  ID_QUIT,
  ID_PRINT,
  ID_TREELIST,
  ID_TEXT_BACK,
  ID_TEXT_FORE,
  ID_TEXT_SELBACK,
  ID_TEXT_SELFORE,
  ID_TEXT_CURSOR,
  ID_DIR_BACK,
  ID_DIR_FORE,
  ID_DIR_SELBACK,
  ID_DIR_SELFORE,
  ID_DIR_LINES,
  ID_RECENTFILE,
  ID_TOGGLE_WRAP,
  ID_FIXED_WRAP,
  ID_SAVE_SETTINGS,
  ID_TEXT,
  ID_STRIP_CR,
  ID_STRIP_SP,
  ID_INCLUDE_PATH,
  ID_SHOW_HELP,
  ID_OVERSTRIKE,
  ID_READONLY,
  ID_FILETIME,
  ID_PREFERENCES,
  ID_TABCOLUMNS,
  ID_WRAPCOLUMNS,
  ID_DELIMITERS,
  ID_INSERTTABS,
  ID_AUTOINDENT,
  ID_BRACEMATCH,
  ID_NUMCHARS,
  ID_INSERT_FILE,
  ID_EXTRACT_FILE,
  ID_WHEELADJUST,
  ID_LAST = enum(FXMainWindow::ID_LAST, 47)

  # Load the named icon from a file
  def loadIcon(filename)
    begin
      filename = File.join("..", "icons", filename)
      icon = nil
      File.open(filename, "rb") { |f|
        icon = FXPNGIcon.new(getApp(), f.read)
      }
      icon
    rescue
      raise RuntimeError, "Couldn't load icon: #{filename}"
    end
  end

  def initialize(app)
    # Call base class initialize first
    super(app, "FOX Text Editor: - untitled", nil, nil, DECOR_ALL,
      0, 0, 850, 600, 0, 0)

    # Set up the message map for this class
    FXMAPFUNC(SEL_TIMEOUT,            ID_FILETIME,      :onCheckFile)
    FXMAPFUNC(SEL_COMMAND,            ID_ABOUT,         :onCmdAbout)
    FXMAPFUNC(SEL_COMMAND,            ID_REOPEN,        :onCmdReopen)
    FXMAPFUNC(SEL_UPDATE,             ID_REOPEN,        :onUpdReopen)
    FXMAPFUNC(SEL_COMMAND,            ID_OPEN,          :onCmdOpen)
    FXMAPFUNC(SEL_COMMAND,            ID_OPEN_SELECTED, :onCmdOpenSelected)
    FXMAPFUNC(SEL_COMMAND,            ID_SAVE,          :onCmdSave)
    FXMAPFUNC(SEL_UPDATE,             ID_SAVE,          :onUpdSave)
    FXMAPFUNC(SEL_COMMAND,            ID_SAVEAS,        :onCmdSaveAs)
    FXMAPFUNC(SEL_COMMAND,            ID_NEW,           :onCmdNew)
    FXMAPFUNC(SEL_UPDATE,             ID_TITLE,         :onUpdTitle)
    FXMAPFUNC(SEL_COMMAND,            ID_FONT,          :onCmdFont)
    FXMAPFUNC(SEL_COMMAND,            ID_QUIT,          :onCmdQuit)
    FXMAPFUNC(SEL_SIGNAL,             ID_QUIT,          :onCmdQuit)
    FXMAPFUNC(SEL_CLOSE,              ID_TITLE,         :onCmdQuit)
    FXMAPFUNC(SEL_COMMAND,            ID_PRINT,         :onCmdPrint)
    FXMAPFUNC(SEL_COMMAND,            ID_TREELIST,      :onCmdTreeList)
    FXMAPFUNC(SEL_COMMAND,            ID_TEXT_BACK,     :onCmdTextBackColor)
    FXMAPFUNC(SEL_CHANGED,            ID_TEXT_BACK,     :onCmdTextBackColor)
    FXMAPFUNC(SEL_UPDATE,             ID_TEXT_BACK,     :onUpdTextBackColor)
    FXMAPFUNC(SEL_COMMAND,            ID_TEXT_SELBACK,  :onCmdTextSelBackColor)
    FXMAPFUNC(SEL_CHANGED,            ID_TEXT_SELBACK,  :onCmdTextSelBackColor)
    FXMAPFUNC(SEL_UPDATE,             ID_TEXT_SELBACK,  :onUpdTextSelBackColor)
    FXMAPFUNC(SEL_COMMAND,            ID_TEXT_FORE,     :onCmdTextForeColor)
    FXMAPFUNC(SEL_CHANGED,            ID_TEXT_FORE,     :onCmdTextForeColor)
    FXMAPFUNC(SEL_UPDATE,             ID_TEXT_FORE,     :onUpdTextForeColor)
    FXMAPFUNC(SEL_COMMAND,            ID_TEXT_SELFORE,  :onCmdTextSelForeColor)
    FXMAPFUNC(SEL_CHANGED,            ID_TEXT_SELFORE,  :onCmdTextSelForeColor)
    FXMAPFUNC(SEL_UPDATE,             ID_TEXT_SELFORE,  :onUpdTextSelForeColor)
    FXMAPFUNC(SEL_COMMAND,            ID_TEXT_CURSOR,   :onCmdTextCursorColor)
    FXMAPFUNC(SEL_CHANGED,            ID_TEXT_CURSOR,   :onCmdTextCursorColor)
    FXMAPFUNC(SEL_UPDATE,             ID_TEXT_CURSOR,   :onUpdTextCursorColor)
    FXMAPFUNC(SEL_COMMAND,            ID_DIR_BACK,      :onCmdDirBackColor)
    FXMAPFUNC(SEL_CHANGED,            ID_DIR_BACK,      :onCmdDirBackColor)
    FXMAPFUNC(SEL_UPDATE,             ID_DIR_BACK,      :onUpdDirBackColor)
    FXMAPFUNC(SEL_COMMAND,            ID_DIR_FORE,      :onCmdDirForeColor)
    FXMAPFUNC(SEL_CHANGED,            ID_DIR_FORE,      :onCmdDirForeColor)
    FXMAPFUNC(SEL_UPDATE,             ID_DIR_FORE,      :onUpdDirForeColor)
    FXMAPFUNC(SEL_COMMAND,            ID_DIR_SELBACK,   :onCmdDirSelBackColor)
    FXMAPFUNC(SEL_CHANGED,            ID_DIR_SELBACK,   :onCmdDirSelBackColor)
    FXMAPFUNC(SEL_UPDATE,             ID_DIR_SELBACK,   :onUpdDirSelBackColor)
    FXMAPFUNC(SEL_COMMAND,            ID_DIR_SELFORE,   :onCmdDirSelForeColor)
    FXMAPFUNC(SEL_CHANGED,            ID_DIR_SELFORE,   :onCmdDirSelForeColor)
    FXMAPFUNC(SEL_UPDATE,             ID_DIR_SELFORE,   :onUpdDirSelForeColor)
    FXMAPFUNC(SEL_COMMAND,            ID_DIR_LINES,     :onCmdDirLineColor)
    FXMAPFUNC(SEL_CHANGED,            ID_DIR_LINES,     :onCmdDirLineColor)
    FXMAPFUNC(SEL_UPDATE,             ID_DIR_LINES,     :onUpdDirLineColor)
    FXMAPFUNC(SEL_COMMAND,            ID_RECENTFILE,    :onCmdRecentFile)
    FXMAPFUNC(SEL_UPDATE,             ID_TOGGLE_WRAP,   :onUpdWrap)
    FXMAPFUNC(SEL_COMMAND,            ID_TOGGLE_WRAP,   :onCmdWrap)
    FXMAPFUNC(SEL_COMMAND,            ID_SAVE_SETTINGS, :onCmdSaveSettings)
    FXMAPFUNC(SEL_INSERTED,           ID_TEXT,          :onTextInserted)
    FXMAPFUNC(SEL_REPLACED,           ID_TEXT,          :onTextReplaced)
    FXMAPFUNC(SEL_DELETED,            ID_TEXT,          :onTextDeleted)
    FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, ID_TEXT,          :onTextRightMouse)
    FXMAPFUNC(SEL_UPDATE,             ID_FIXED_WRAP,    :onUpdWrapFixed)
    FXMAPFUNC(SEL_COMMAND,            ID_FIXED_WRAP,    :onCmdWrapFixed)
    FXMAPFUNC(SEL_DND_MOTION,         ID_TEXT,          :onEditDNDMotion)
    FXMAPFUNC(SEL_DND_DROP,           ID_TEXT,          :onEditDNDDrop)
    FXMAPFUNC(SEL_UPDATE,             ID_STRIP_CR,      :onUpdStripReturns)
    FXMAPFUNC(SEL_COMMAND,            ID_STRIP_CR,      :onCmdStripReturns)
    FXMAPFUNC(SEL_UPDATE,             ID_STRIP_SP,      :onUpdStripSpaces)
    FXMAPFUNC(SEL_COMMAND,            ID_STRIP_SP,      :onCmdStripSpaces)
    FXMAPFUNC(SEL_COMMAND,            ID_INCLUDE_PATH,  :onCmdIncludePaths)
    FXMAPFUNC(SEL_COMMAND,            ID_SHOW_HELP,     :onCmdShowHelp)
    FXMAPFUNC(SEL_COMMAND,            ID_FILEFILTER,    :onCmdFilter)
    FXMAPFUNC(SEL_UPDATE,             ID_OVERSTRIKE,    :onUpdOverstrike)
    FXMAPFUNC(SEL_UPDATE,             ID_READONLY,      :onUpdReadOnly)
    FXMAPFUNC(SEL_UPDATE,             ID_NUMCHARS,      :onUpdNumChars)
    FXMAPFUNC(SEL_COMMAND,            ID_PREFERENCES,   :onCmdPreferences)
    FXMAPFUNC(SEL_COMMAND,            ID_TABCOLUMNS,    :onCmdTabColumns)
    FXMAPFUNC(SEL_UPDATE,             ID_TABCOLUMNS,    :onUpdTabColumns)
    FXMAPFUNC(SEL_COMMAND,            ID_DELIMITERS,    :onCmdDelimiters)
    FXMAPFUNC(SEL_UPDATE,             ID_DELIMITERS,    :onUpdDelimiters)
    FXMAPFUNC(SEL_COMMAND,            ID_WRAPCOLUMNS,   :onCmdWrapColumns)
    FXMAPFUNC(SEL_UPDATE,             ID_WRAPCOLUMNS,   :onUpdWrapColumns)
    FXMAPFUNC(SEL_COMMAND,            ID_AUTOINDENT,    :onCmdAutoIndent)
    FXMAPFUNC(SEL_UPDATE,             ID_AUTOINDENT,    :onUpdAutoIndent)
    FXMAPFUNC(SEL_COMMAND,            ID_INSERTTABS,    :onCmdInsertTabs)
    FXMAPFUNC(SEL_UPDATE,             ID_INSERTTABS,    :onUpdInsertTabs)
    FXMAPFUNC(SEL_COMMAND,            ID_BRACEMATCH,    :onCmdBraceMatch)
    FXMAPFUNC(SEL_UPDATE,             ID_BRACEMATCH,    :onUpdBraceMatch)
    FXMAPFUNC(SEL_UPDATE,             ID_INSERT_FILE,   :onUpdInsertFile)
    FXMAPFUNC(SEL_COMMAND,            ID_INSERT_FILE,   :onCmdInsertFile)
    FXMAPFUNC(SEL_UPDATE,             ID_EXTRACT_FILE,  :onUpdExtractFile)
    FXMAPFUNC(SEL_COMMAND,            ID_EXTRACT_FILE,  :onCmdExtractFile)
    FXMAPFUNC(SEL_UPDATE,             ID_WHEELADJUST,   :onUpdWheelAdjust)
    FXMAPFUNC(SEL_COMMAND,            ID_WHEELADJUST,   :onCmdWheelAdjust)

    # Undoable commands
    @undolist = FXUndoList.new

    # Default font
    @font = nil
    # Make some icons
    @bigicon = loadIcon("big.png")
    @smallicon = loadIcon("small.png")
    @newicon = loadIcon("filenew.png")
    @openicon = loadIcon("fileopen.png")
    @saveicon = loadIcon("filesave.png")
    @saveasicon = FXPNGIcon.new(getApp(), File.open(File.join("..", "icons", "saveas.png"), "rb").read(),
      0, IMAGE_ALPHAGUESS)
    @printicon = loadIcon("printicon.png")
    @cuticon = loadIcon("cut.png")
    @copyicon = loadIcon("copy.png")
    @pasteicon = loadIcon("paste.png")
    @deleteicon = loadIcon("kill.png")
    @undoicon = loadIcon("undo.png")
    @redoicon = loadIcon("redo.png")
    @fontsicon = loadIcon("fonts.png")
    @helpicon = loadIcon("help.png")

    # Application icons
    setIcon(@bigicon)
    setMiniIcon(@smallicon)
    # Make main window; set myself as the target
    setTarget(self)
    setSelector(ID_TITLE)
    # Help window
    @helpwindow = HelpWindow.new(self)
    # Make menu bar
    dragshell1 = FXToolBarShell.new(self, FRAME_RAISED|FRAME_THICK)
    menubar = FXMenuBar.new(self, dragshell1, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
    FXToolBarGrip.new(menubar, menubar, FXMenuBar::ID_TOOLBARGRIP,
      TOOLBARGRIP_DOUBLE)
    # Tool bar
    dragshell2 = FXToolBarShell.new(self, FRAME_RAISED|FRAME_THICK)
    toolbar = FXToolBar.new(self, dragshell2,
      LAYOUT_SIDE_TOP|LAYOUT_FILL_X|PACK_UNIFORM_WIDTH|PACK_UNIFORM_HEIGHT)
    FXToolBarGrip.new(toolbar, toolbar, FXToolBar::ID_TOOLBARGRIP,
      TOOLBARGRIP_DOUBLE)
    # Status bar
    statusbar = FXStatusBar.new(self,
      LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|STATUSBAR_WITH_DRAGCORNER)
    # Info about the editor
    FXButton.new(statusbar, "\tThe FOX Text Editor\tAbout the FOX Text Editor.",
      @smallicon, self, ID_ABOUT, LAYOUT_FILL_Y|LAYOUT_RIGHT)
    # File menu
    filemenu = FXMenuPane.new(self)
    FXMenuTitle.new(menubar, "&File", nil, filemenu)
    # Edit Menu
    editmenu = FXMenuPane.new(self)
    FXMenuTitle.new(menubar, "&Edit", nil, editmenu)
    # Goto Menu
    gotomenu = FXMenuPane.new(self)
    FXMenuTitle.new(menubar, "&Goto", nil, gotomenu)
    # Search Menu
    searchmenu = FXMenuPane.new(self)
    FXMenuTitle.new(menubar, "&Search", nil, searchmenu)
    # Options Menu
    optionmenu = FXMenuPane.new(self)
    FXMenuTitle.new(menubar, "&Options", nil, optionmenu)
    # View menu
    viewmenu = FXMenuPane.new(self)
    FXMenuTitle.new(menubar, "&View", nil, viewmenu)
    # Help menu
    helpmenu = FXMenuPane.new(self)
    FXMenuTitle.new(menubar, "&Help", nil, helpmenu, LAYOUT_RIGHT)
    # Splitter
    splitter = FXSplitter.new(self,
      LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y|SPLITTER_TRACKING)
    # Sunken border for tree
    @treebox = FXVerticalFrame.new(splitter, LAYOUT_FILL_X|LAYOUT_FILL_Y,
      0, 0, 0, 0, 0, 0, 0, 0)
    # Make tree
    treeframe = FXHorizontalFrame.new(@treebox,
      FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y,
      0, 0, 0, 0, 0, 0, 0, 0)
    @dirlist = FXDirList.new(treeframe, self, ID_TREELIST,
      (DIRLIST_SHOWFILES|TREELIST_BROWSESELECT|TREELIST_SHOWS_LINES|
       TREELIST_SHOWS_BOXES|LAYOUT_FILL_X|LAYOUT_FILL_Y))
    filterframe = FXHorizontalFrame.new(@treebox, LAYOUT_FILL_X)
    FXLabel.new(filterframe, "Filter:")
    @filter = FXComboBox.new(filterframe, 25, self, ID_FILEFILTER,
      COMBOBOX_STATIC|LAYOUT_FILL_X|FRAME_SUNKEN|FRAME_THICK)
    @filter.numVisible = 4
    # Sunken border for text widget
    textbox = FXHorizontalFrame.new(splitter,
      FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0)
    # Make editor window
    @editor = FXText.new(textbox, self, ID_TEXT, LAYOUT_FILL_X|LAYOUT_FILL_Y)
    @editor.hiliteMatchTime = 300000
    # Show readonly state in status bar
    readonly = FXLabel.new(statusbar, nil, nil, FRAME_SUNKEN|LAYOUT_RIGHT|LAYOUT_CENTER_Y)
    readonly.padLeft = 2
    readonly.padRight = 2
    readonly.padTop = 1
    readonly.padBottom = 1
    readonly.setTarget(self)
    readonly.setSelector(ID_READONLY)
    # Show insert mode in status bar
    overstrike = FXLabel.new(statusbar, nil, nil, FRAME_SUNKEN|LAYOUT_RIGHT|LAYOUT_CENTER_Y)
    overstrike.padLeft = 2
    overstrike.padRight = 2
    overstrike.padTop = 1
    overstrike.padBottom = 1
    overstrike.setTarget(self)
    overstrike.setSelector(ID_OVERSTRIKE)
    # Show size of text in status bar
    numchars = FXTextField.new(statusbar, 6, self, ID_NUMCHARS,
      FRAME_SUNKEN|JUSTIFY_RIGHT|LAYOUT_RIGHT|LAYOUT_CENTER_Y,
      0, 0, 0, 0, 2, 2, 1, 1)
    numchars.backColor = statusbar.backColor
    # Caption before number
    FXLabel.new(statusbar, "  Size:", nil, LAYOUT_RIGHT|LAYOUT_CENTER_Y)
    # Show column number in status bar
    columnno = FXTextField.new(statusbar, 4, @editor, FXText::ID_CURSOR_COLUMN,
      FRAME_SUNKEN|JUSTIFY_RIGHT|LAYOUT_RIGHT|LAYOUT_CENTER_Y,
      0, 0, 0, 0, 2, 2, 1, 1)
    columnno.backColor = statusbar.backColor
    # Caption before number
    FXLabel.new(statusbar, "  Col:", nil, LAYOUT_RIGHT|LAYOUT_CENTER_Y)
    # Show line number in status bar
    rowno = FXTextField.new(statusbar, 4, @editor, FXText::ID_CURSOR_ROW,
      FRAME_SUNKEN|JUSTIFY_RIGHT|LAYOUT_RIGHT|LAYOUT_CENTER_Y,
      0, 0, 0, 0, 2, 2, 1, 1)
    rowno.backColor = statusbar.backColor
    # Caption before number
    FXLabel.new(statusbar, "  Line:", nil, LAYOUT_RIGHT|LAYOUT_CENTER_Y)
    # Toobar buttons: File manipulation
    FXButton.new(toolbar, "New\tNew\tCreate new document.", @newicon,
      self, ID_NEW, (ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED|
      LAYOUT_TOP|LAYOUT_LEFT))
    FXButton.new(toolbar, "Open\tOpen\tOpen document file.", @openicon,
      self, ID_OPEN, (ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED|
      LAYOUT_TOP|LAYOUT_LEFT))
    FXButton.new(toolbar, "Save\tSave\tSave document.", @saveicon,
      self, ID_SAVE, (ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED|
      LAYOUT_TOP|LAYOUT_LEFT))
    FXButton.new(toolbar, "Save as\tSave As\tSave document to another file.",
      @saveasicon, self, ID_SAVEAS, (ICON_ABOVE_TEXT|BUTTON_TOOLBAR|
      FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT))
    # Toobar buttons: Print
    FXFrame.new(toolbar,
      LAYOUT_TOP|LAYOUT_LEFT|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, 5, 5)
    FXButton.new(toolbar, "Print\tPrint\tPrint document.", @printicon,
      self, ID_PRINT, (ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED|
      LAYOUT_TOP|LAYOUT_LEFT))
    # Toobar buttons: Editing
    FXFrame.new(toolbar,
      LAYOUT_TOP|LAYOUT_LEFT|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, 5, 5)
    FXButton.new(toolbar, "Cut\tCut\tCut selection to clipboard.", @cuticon,
      @editor, FXText::ID_CUT_SEL, (ICON_ABOVE_TEXT|BUTTON_TOOLBAR|
      FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT))
    FXButton.new(toolbar, "Copy\tCopy\tCopy selection to clipboard.", @copyicon,
      @editor, FXText::ID_COPY_SEL, (ICON_ABOVE_TEXT|BUTTON_TOOLBAR|
      FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT))
    FXButton.new(toolbar, "Paste\tPaste\tPaste clipboard.", @pasteicon,
      @editor, FXText::ID_PASTE_SEL, (ICON_ABOVE_TEXT|BUTTON_TOOLBAR|
      FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT))
    FXButton.new(toolbar, "Undo\tUndo\tUndo last change.", @undoicon,
      @undolist, FXUndoList::ID_UNDO, (ICON_ABOVE_TEXT|BUTTON_TOOLBAR|
      FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT))
    FXButton.new(toolbar, "Redo\tRedo\tRedo last undo.", @redoicon,
      @undolist, FXUndoList::ID_REDO, (ICON_ABOVE_TEXT|BUTTON_TOOLBAR|
      FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT))
    # Color
    FXFrame.new(toolbar,
      LAYOUT_TOP|LAYOUT_LEFT|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, 5, 5)
    FXButton.new(toolbar, "Fonts\tFonts\tDisplay font dialog.", @fontsicon,
      self, ID_FONT, (ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED|
      LAYOUT_TOP|LAYOUT_LEFT))
    FXButton.new(toolbar, "Help\tHelp on editor\tDisplay help information.",
      @helpicon, self, ID_SHOW_HELP, (ICON_ABOVE_TEXT|BUTTON_TOOLBAR|
      FRAME_RAISED|LAYOUT_TOP|LAYOUT_RIGHT))
    # File Menu entries
    FXMenuCommand.new(filemenu, "&Open...        \tCtl-O\tOpen document file.",
      @openicon, self, ID_OPEN)
    FXMenuCommand.new(filemenu,
      "Open Selected...   \tCtl-E\tOpen highlighted document file.", nil,
      self, ID_OPEN_SELECTED)
    FXMenuCommand.new(filemenu, "&Reopen...\t\tReopen file.", nil,
      self, ID_REOPEN)
    FXMenuCommand.new(filemenu, "&New...\tCtl-N\tCreate new document.",
      @newicon, self, ID_NEW)
    FXMenuCommand.new(filemenu, "&Save\tCtl-S\tSave changes to file.",
      @saveicon, self, ID_SAVE)
    FXMenuCommand.new(filemenu, "Save &As...\t\tSave document to another file.",
      @saveasicon, self, ID_SAVEAS)
    FXMenuSeparator.new(filemenu)
    FXMenuCommand.new(filemenu, "Insert from file...\t\tInsert text from file.",
      nil, self, ID_INSERT_FILE)
    FXMenuCommand.new(filemenu, "Extract to file...\t\tExtract text to file.",
      nil, self, ID_EXTRACT_FILE)
    FXMenuCommand.new(filemenu, "&Print...\tCtl-P\tPrint document.", @printicon,
      self, ID_PRINT)
    FXMenuCommand.new(filemenu, "&Editable\t\tDocument editable.", nil,
      @editor, FXText::ID_TOGGLE_EDITABLE)
    iconifyCmd = FXMenuCommand.new(filemenu, "&Iconify...\t\tIconify editor.")
    iconifyCmd.connect(SEL_COMMAND) { self.minimize }
    # Recent file menu; this automatically hides if there are no files
    sep1 = FXMenuSeparator.new(filemenu)
    sep1.setTarget(@mrufiles)
    sep1.setSelector(FXRecentFiles::ID_ANYFILES)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_1)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_2)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_3)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_4)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_5)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_6)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_7)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_8)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_9)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_10)
    FXMenuCommand.new(filemenu, "&Clear Recent Files", nil,
      @mrufiles, FXRecentFiles::ID_CLEAR)
    sep2 = FXMenuSeparator.new(filemenu)
    sep2.setTarget(@mrufiles)
    sep2.setSelector(FXRecentFiles::ID_ANYFILES)
    FXMenuCommand.new(filemenu, "&Quit\tCtl-Q", nil, self, ID_QUIT)
    # Edit Menu entries
    FXMenuCommand.new(editmenu, "&Undo\tCtl-Z\tUndo last change.", @undoicon,
      @undolist, FXUndoList::ID_UNDO)
    FXMenuCommand.new(editmenu, "&Redo\tCtl-Y\tRedo last undo.", @redoicon,
      @undolist, FXUndoList::ID_REDO)
    FXMenuCommand.new(editmenu, "&Undo all\t\tUndo all.", nil,
      @undolist, FXUndoList::ID_UNDO_ALL)
    FXMenuCommand.new(editmenu, "&Redo all\t\tRedo all.", nil,
      @undolist, FXUndoList::ID_REDO_ALL)
    FXMenuCommand.new(editmenu, "&Revert to saved\t\tRevert to saved.", nil,
      @undolist, FXUndoList::ID_REVERT)
    FXMenuSeparator.new(editmenu)
    FXMenuCommand.new(editmenu, "&Copy\tCtl-C\tCopy selection to clipboard.",
      @copyicon, @editor, FXText::ID_COPY_SEL)
    FXMenuCommand.new(editmenu, "Cu&t\tCtl-X\tCut selection to clipboard.",
      @cuticon, @editor, FXText::ID_CUT_SEL)
    FXMenuCommand.new(editmenu, "&Paste\tCtl-V\tPaste from clipboard.",
      @pasteicon, @editor, FXText::ID_PASTE_SEL)
    FXMenuCommand.new(editmenu, "&Delete\t\tDelete selection.", @deleteicon,
      @editor, FXText::ID_DELETE_SEL)
    FXMenuSeparator.new(editmenu)
    FXMenuCommand.new(editmenu, "Lo&wer-case\tCtl-6\tChange to lower case.",
      nil, @editor, FXText::ID_LOWER_CASE)
    FXMenuCommand.new(editmenu,
      "Upp&er-case\tShift-Ctl-^\tChange to upper case.", nil,
      @editor, FXText::ID_UPPER_CASE)
    FXMenuCommand.new(editmenu,
      "Clean indent\t\tClean indentation to either all tabs or all spaces.",
      nil, @editor, FXText::ID_CLEAN_INDENT)
    FXMenuCommand.new(editmenu, "Shift left\tCtl-9\tShift text left.", nil,
      @editor, FXText::ID_SHIFT_LEFT)
    FXMenuCommand.new(editmenu, "Shift right\tCtl-0\tShift text right.", nil,
      @editor, FXText::ID_SHIFT_RIGHT)
    FXMenuCommand.new(editmenu,
      "Shift tab left\t\tShift text left one tab position.", nil,
      @editor, FXText::ID_SHIFT_TABLEFT)
    FXMenuCommand.new(editmenu,
      "Shift tab right\t\tShift text right one tab position.", nil,
      @editor, FXText::ID_SHIFT_TABRIGHT)
    # Goto Menu entries
    FXMenuCommand.new(gotomenu,
      "&Goto...\tCtl-G\tGoto line number.", nil,
      @editor, FXText::ID_GOTO_LINE)
    FXMenuCommand.new(gotomenu,
      "Goto selected...\tCtl-L\tGoto selected line number.", nil,
      @editor, FXText::ID_GOTO_SELECTED)
    FXMenuSeparator.new(gotomenu)
    FXMenuCommand.new(gotomenu,
      "Goto {..\tShift-Ctl-{\tGoto start of enclosing block.", nil,
      @editor, FXText::ID_LEFT_BRACE)
    FXMenuCommand.new(gotomenu,
      "Goto ..}\tShift-Ctl-}\tGoto end of enclosing block.", nil,
      @editor, FXText::ID_RIGHT_BRACE)
    FXMenuCommand.new(gotomenu,
      "Goto (..\tShift-Ctl-(\tGoto start of enclosing expression.", nil,
      @editor, FXText::ID_LEFT_PAREN)
    FXMenuCommand.new(gotomenu,
      "Goto ..)\tShift-Ctl-)\tGoto end of enclosing expression.", nil,
      @editor, FXText::ID_RIGHT_PAREN)
    FXMenuSeparator.new(gotomenu)
    FXMenuCommand.new(searchmenu,
      "Goto matching (..)\tCtl-M\tGoto matching brace or parenthesis.", nil,
      @editor, FXText::ID_GOTO_MATCHING)
    # Search Menu entries
    FXMenuCommand.new(searchmenu,
      "Select matching (..)\tShift-Ctl-M\tSelect matching brace or parenthesis.", nil,
      @editor, FXText::ID_SELECT_MATCHING)
    FXMenuCommand.new(searchmenu,
      "Select block {..}\tShift-Alt-{\tSelect enclosing block.", nil,
      @editor, FXText::ID_SELECT_BRACE)
    FXMenuCommand.new(searchmenu,
      "Select block {..}\tShift-Alt-}\tSelect enclosing block.", nil,
      @editor, FXText::ID_SELECT_BRACE)
    FXMenuCommand.new(searchmenu,
      "Select expression (..)\tShift-Alt-(\tSelect enclosing parentheses.", nil,
      @editor, FXText::ID_SELECT_PAREN)
    FXMenuCommand.new(searchmenu,
      "Select expression (..)\tShift-Alt-)\tSelect enclosing parentheses.", nil,
      @editor, FXText::ID_SELECT_PAREN)
    FXMenuSeparator.new(searchmenu)
    FXMenuCommand.new(searchmenu,
      "&Search sel. fwd\tCtl-H\tSearch for selection.", nil,
      @editor, FXText::ID_SEARCH_FORW_SEL)
    FXMenuCommand.new(searchmenu,
      "&Search sel. bck\tShift-Ctl-H\tSearch for selection.", nil,
      @editor, FXText::ID_SEARCH_BACK_SEL)
    FXMenuCommand.new(searchmenu,
      "&Search...\tCtl-F\tSearch for a string.", nil,
      @editor, FXText::ID_SEARCH)
    FXMenuCommand.new(searchmenu,
      "R&eplace...\tCtl-R\tSearch for a string.", nil,
      @editor, FXText::ID_REPLACE)
    # Options menu
    FXMenuCommand.new(optionmenu,
      "Preferences...\t\tChange preferences.", nil,
      self, TextWindow::ID_PREFERENCES)
    FXMenuCommand.new(optionmenu,
      "Font...\t\tChange text font.", @fontsicon, self, ID_FONT)
    FXMenuCommand.new(optionmenu,
      "Overstrike\t\tToggle overstrike mode.", nil,
      @editor, FXText::ID_TOGGLE_OVERSTRIKE)
    FXMenuCommand.new(optionmenu,
      "Include path...\t\tDirectories to search for include files.", nil,
      self, TextWindow::ID_INCLUDE_PATH)
    FXMenuCommand.new(optionmenu,
      "Save Settings...\t\tSave settings now.", nil,
      self, TextWindow::ID_SAVE_SETTINGS)
    # View Menu entries
    FXMenuCommand.new(viewmenu,
      "Hidden files\t\tShow hidden files and directories.", nil,
      @dirlist, FXDirList::ID_TOGGLE_HIDDEN)
    FXMenuCommand.new(viewmenu,
      "File Browser\t\tDisplay file list.", nil,
      @treebox,FXWindow::ID_TOGGLESHOWN)
    FXMenuCommand.new(viewmenu, "Toolbar\t\tDisplay toolbar.", nil,
      toolbar, FXWindow::ID_TOGGLESHOWN)
    FXMenuCommand.new(viewmenu, "Status line\t\tDisplay status line.", nil,
      statusbar, FXWindow::ID_TOGGLESHOWN)
    # Help Menu entries
    FXMenuCommand.new(helpmenu, "&Help...\t\tDisplay help information.",
      @helpicon, self, ID_SHOW_HELP, 0)
    FXMenuSeparator.new(helpmenu)
    FXMenuCommand.new(helpmenu, "&About TextEdit...\t\tDisplay about panel.",
      @smallicon, self, ID_ABOUT, 0)
    # Make a tool tip
    FXToolTip.new(getApp(), 0)
    # Recent files
    @mrufiles = FXRecentFiles.new
    @mrufiles.setTarget(self)
    @mrufiles.setSelector(ID_RECENTFILE)
    # Add some alternative accelerators
    if getAccelTable()
      getAccelTable().addAccel(MKUINT(KEY_Z, CONTROLMASK|SHIFTMASK),
                               @undolist,
                               MKUINT(FXUndoList::ID_REDO, SEL_COMMAND))
    end
    # Initialize file name
    @filename = "untitled"
    @filetime = nil
    @filenameset = false
    # Initialize other stuff
    @searchpath = "/usr/include"
    setPatterns(["All Files (*)"])
    setCurrentPattern(0)
    @timer = nil
    @stripcr = true
    @stripsp = false
    @undolist.mark
  end


  # Load file
  def loadFile(file)
    begin
      getApp().beginWaitCursor()
      text = File.open(file, "r").read
      text.gsub!('\r', '') if @stripcr
      @editor.text = text
    ensure
      getApp().endWaitCursor()
    end

    # Set stuff
    @editor.modified = false
    @editor.editable = File.stat(file).writable?
    @dirlist.currentFile = file
    @mrufiles.appendFile(file)
    @filetime = File.mtime(file)
    @filename = file
    @filenameset = true
    @undolist.clear
    @undolist.mark
  end


  # Insert file
  def insertFile(file)
    begin
      getApp().beginWaitCursor()
      text = File.open(file, "r").read
      text.gsub!('\r', '') if @stripcr
      @editor.insertText(@editor.cursorPos, text, n, true)
      @editor.modified = true
    ensure
      getApp().endWaitCursor()
    end
  end


  # Save file
  def saveFile(file)
    # Set wait cursor
    getApp().beginWaitCursor()

    # Get text from editor
    text = @editor.text

    # Strip trailing spaces
    if @stripsp
      lines = text.split('\n')
      lines.each { |line|
        line.sub!(/ *$/, "")
      }
      text = lines.join('\n')
    end

    # Write the file
    File.open(file, "w").write(text)

    # Kill wait cursor
    getApp().endWaitCursor()

    # Set stuff
    @editor.modified = false
    @editor.editable = true
    @dirlist.currentFile = file
    @mrufiles.appendFile(file)
    @filetime = File.mtime(file)
    @filename = file
    @filenameset = true
    @undolist.mark
  end


  # Extract file
  def extractFile(file)
    # Set wait cursor
    getApp().beginWaitCursor()

    # Get text from editor
    size = @editor.selEndPos - @editor.selStartPos
    text = @editor.extractText(@editor.selStartPos, size)

    # Strip trailing spaces
    if @stripsp
      lines = text.split('\n')
      lines.each { |line|
        line.sub!(/ *$/, "")
      }
      text = lines.join('\n')
    end

    # Write the file
    File.open(file, "w").write(text)

    # Kill wait cursor
    getApp().endWaitCursor()
  end


  # Read settings from registry
  def readRegistry
    # Text colors
    textback    = getApp().reg().readColorEntry("SETTINGS", "textbackground", @editor.backColor)
    textfore    = getApp().reg().readColorEntry("SETTINGS", "textforeground", @editor.textColor)
    textselback = getApp().reg().readColorEntry("SETTINGS", "textselbackground", @editor.selBackColor)
    textselfore = getApp().reg().readColorEntry("SETTINGS", "textselforeground", @editor.selTextColor)
    textcursor  = getApp().reg().readColorEntry("SETTINGS", "textcursor", @editor.cursorColor)

    # Directory colors
    dirback    = getApp().reg().readColorEntry("SETTINGS", "browserbackground", @dirlist.backColor)
    dirfore    = getApp().reg().readColorEntry("SETTINGS", "browserforeground", @dirlist.textColor)
    dirselback = getApp().reg().readColorEntry("SETTINGS", "browserselbackground", @dirlist.selBackColor)
    dirselfore = getApp().reg().readColorEntry("SETTINGS", "browserselforeground", @dirlist.selTextColor)
    dirlines   = getApp().reg().readColorEntry("SETTINGS", "browserlines", @dirlist.lineColor)

    # Delimiters
    delimiters = getApp().reg().readStringEntry("SETTINGS", "delimiters", '~.,/\\`\'!@#$%^&*()-=+{}|[]":;<>?')

    # Font
    fontspec = getApp().reg().readStringEntry("SETTINGS", "font", "")
    if fontspec != ""
      font = FXFont.new(getApp(), fontspec)
      @editor.font = font
    end

    # Get size
    xx = getApp().reg().readIntEntry("SETTINGS", "x", 5)
    yy = getApp().reg().readIntEntry("SETTINGS", "y", 5)
    ww = getApp().reg().readIntEntry("SETTINGS", "width", 600)
    hh = getApp().reg().readIntEntry("SETTINGS", "height", 400)

    # Hidden files shown
    hiddenfiles = getApp().reg().readIntEntry("SETTINGS", "showhiddenfiles", 0)
    @dirlist.hiddenFilesShown = (hiddenfiles != 0) ? true : false

    # Showing the tree?
    hidetree = getApp().reg().readIntEntry("SETTINGS", "hidetree", 1)

    # Width of tree
    treewidth = getApp().reg().readIntEntry("SETTINGS", "treewidth", 100)

    # Word wrapping
    wrapping = getApp().reg().readIntEntry("SETTINGS", "wordwrap", 0)
    wrapcols = getApp().reg().readIntEntry("SETTINGS", "wrapcols", 80)
    fixedwrap = getApp().reg().readIntEntry("SETTINGS", "fixedwrap", 1)

    # Tab settings, autoindent
    autoindent = getApp().reg().readIntEntry("SETTINGS", "autoindent", 0)
    hardtabs = getApp().reg().readIntEntry("SETTINGS", "hardtabs", 1)
    tabcols = getApp().reg().readIntEntry("SETTINGS", "tabcols", 8)

    # Strip returns
    @stripcr = getApp().reg().readIntEntry("SETTINGS", "stripreturn", 0)
    @stripcr = (@stripcr != 0) ? true : false
    @stripsp = getApp().reg().readIntEntry("SETTINGS", "stripspaces", 0)
    @stripsp = (@stripsp != 0) ? true : false

    # File patterns
    patterns = getApp().reg().readStringEntry("SETTINGS", "filepatterns", "All Files (*)")
    setPatterns(patterns.split("\n"))
    setCurrentPattern(getApp().reg().readIntEntry("SETTINGS", "filepatternno", 0))

    # Search path
    searchpath = getApp().reg().readStringEntry("SETTINGS", "searchpath", "/usr/include")

    # Change the colors
    @editor.textColor    = textfore
    @editor.backColor    = textback
    @editor.selBackColor = textselback
    @editor.selTextColor = textselfore
    @editor.cursorColor  = textcursor
    @dirlist.textColor    = dirfore
    @dirlist.backColor    = dirback
    @dirlist.selBackColor = dirselback
    @dirlist.selTextColor = dirselfore
    @dirlist.lineColor    = dirlines
    # Change delimiters
    @editor.delimiters = delimiters
    # Hide tree if asked for
    @treebox.hide if hidetree
    # Set tree width
    @treebox.width = treewidth
    # Open toward file
    @dirlist.currentFile = @filename
    # Wrap mode
    if wrapping
      @editor.textStyle |=  TEXT_WORDWRAP
    else
      @editor.textStyle &= ~TEXT_WORDWRAP
    end
    # Wrap fixed mode
    if fixedwrap
      @editor.textStyle |=  TEXT_FIXEDWRAP
    else
      @editor.textStyle &= ~TEXT_FIXEDWRAP
    end
    # Autoindent
    if autoindent
      @editor.textStyle |=  TEXT_AUTOINDENT
    else
      @editor.textStyle &= ~TEXT_AUTOINDENT
    end
    # Hard tabs
    if hardtabs
      @editor.textStyle &= ~TEXT_NO_TABS
    else
      @editor.textStyle |=  TEXT_NO_TABS
    end
    # Wrap and tab columns
    @editor.wrapColumns = wrapcols
    @editor.tabColumns = tabcols
    # Reposition window
    position(xx, yy, ww, hh)
  end


  # Save settings to registry
  def writeRegistry
    # Colors of text
    getApp().reg().writeColorEntry("SETTINGS", "textbackground", @editor.backColor)
    getApp().reg().writeColorEntry("SETTINGS", "textforeground", @editor.textColor)
    getApp().reg().writeColorEntry("SETTINGS", "textselbackground", @editor.selBackColor)
    getApp().reg().writeColorEntry("SETTINGS", "textselforeground", @editor.selTextColor)
    getApp().reg().writeColorEntry("SETTINGS", "textcursor", @editor.cursorColor)
    # Colors of directory
    getApp().reg().writeColorEntry("SETTINGS", "browserbackground", @dirlist.backColor)
    getApp().reg().writeColorEntry("SETTINGS", "browserforeground", @dirlist.textColor)
    getApp().reg().writeColorEntry("SETTINGS", "browserselbackground", @dirlist.selBackColor)
    getApp().reg().writeColorEntry("SETTINGS", "browserselforeground", @dirlist.selTextColor)
    getApp().reg().writeColorEntry("SETTINGS", "browserlines", @dirlist.lineColor)
    # Delimiters
    getApp().reg().writeStringEntry("SETTINGS", "delimiters", @editor.delimiters)
    # Write new window size back to registry
    getApp().reg().writeIntEntry("SETTINGS", "x", getX())
    getApp().reg().writeIntEntry("SETTINGS", "y", getY())
    getApp().reg().writeIntEntry("SETTINGS", "width", getWidth())
    getApp().reg().writeIntEntry("SETTINGS", "height", getHeight())
    # Were showing hidden files
    getApp().reg().writeIntEntry("SETTINGS", "showhiddenfiles", @dirlist.hiddenFilesShown? ? 1 : 0)
    # Was tree shown?
    getApp().reg().writeIntEntry("SETTINGS", "hidetree", @treebox.shown() ? 0 : 1)
    # Width of tree
    getApp().reg().writeIntEntry("SETTINGS", "treewidth", @treebox.getWidth())
    # Wrap mode
    getApp().reg().writeIntEntry("SETTINGS", "wordwrap", (@editor.textStyle & TEXT_WORDWRAP) != 0 ? 1 : 0)
    getApp().reg().writeIntEntry("SETTINGS", "fixedwrap", (@editor.textStyle & TEXT_FIXEDWRAP) != 0 ? 1 : 0)
    getApp().reg().writeIntEntry("SETTINGS", "wrapcols", @editor.getWrapColumns())
    # Tab settings, autoindent
    getApp().reg().writeIntEntry("SETTINGS", "autoindent", (@editor.textStyle & TEXT_AUTOINDENT) != 0 ? 1 : 0)
    getApp().reg().writeIntEntry("SETTINGS", "hardtabs", (@editor.textStyle & TEXT_NO_TABS) == 0 ? 1 : 0)
    getApp().reg().writeIntEntry("SETTINGS", "tabcols", @editor.getTabColumns())
    # Strip returns
    getApp().reg().writeIntEntry("SETTINGS", "stripreturn", @stripcr ? 1 : 0)
    getApp().reg().writeIntEntry("SETTINGS", "stripspaces", @stripsp ? 1 : 0)
    # File patterns
    getApp().reg().writeIntEntry("SETTINGS", "filepatternno", getCurrentPattern())
    patterns = getPatterns().join("\n")
    getApp().reg().writeStringEntry("SETTINGS", "filepatterns", patterns)
    # Search path
    getApp().reg().writeStringEntry("SETTINGS", "searchpath", @searchpath)
    # Font
    getApp().reg().writeStringEntry("SETTINGS", "font", @editor.font.font)
  end

  # About box
  def onCmdAbout(sender, sel, ptr)
    about = FXMessageBox.new(self, "FOX Text Editor",
      "The FOX Text Editor\n\nUsing FOX Library Version #{fxversion[0]}.#{fxversion[1]}.#{fxversion[2]}\n\nCopyright (C) 2000,2001 Jeroen van der Zijp (jvz@cfdrc.com)", @bigicon, MBOX_OK|DECOR_TITLE|DECOR_BORDER)
    about.execute
    return 1
  end


  # Change font
  def onCmdFont(sender, sel, ptr)
    fontdlg = FXFontDialog.new(self, "Change Font", DECOR_BORDER|DECOR_TITLE)
    fontdesc = @editor.font.fontDesc
    fontdlg.fontSelection = fontdesc
    if fontdlg.execute() != 0
      fontdesc = fontdlg.fontSelection
      font = FXFont.new(getApp(), fontdesc)
      font.create
      @editor.font = font
      @editor.update
    end
    return 1
  end


  # Save settings
  def onCmdSaveSettings(sender, sel, ptr)
    writeRegistry();
    getApp().reg().write
    return 1
  end


  # Toggle wrap mode
  def onCmdWrap(sender, sel, ptr)
    @editor.textStyle ^= TEXT_WORDWRAP
    return 1
  end


  # Update toggle wrap mode
  def onUpdWrap(sender, sel, ptr)
    if (@editor.textStyle & TEXT_WORDWRAP) != 0
      sender.handle(self, MKUINT(ID_CHECK, SEL_COMMAND), nil)
    else
      sender.handle(self, MKUINT(ID_UNCHECK, SEL_COMMAND), nil)
    end
    return 1
  end


  # Toggle fixed wrap mode
  def onCmdWrapFixed(sender, sel, ptr)
    @editor.textStyle ^= TEXT_FIXEDWRAP
    return 1
  end


  # Update toggle fixed wrap mode
  def onUpdWrapFixed(sender, sel, ptr)
    if (@editor.textStyle & TEXT_FIXEDWRAP) != 0
      sender.handle(self, MKUINT(ID_CHECK, SEL_COMMAND), nil)
    else
      sender.handle(self, MKUINT(ID_UNCHECK, SEL_COMMAND), nil)
    end
    return 1
  end

  # Toggle strip returns mode
  def onCmdStripReturns(sender, sel, ptr)
    @stripcr = !@stripcr
    return 1
  end


  # Update toggle strip returns mode
  def onUpdStripReturns(sender, sel, ptr)
    if @stripcr
      sender.handle(self, MKUINT(ID_CHECK, SEL_COMMAND), nil)
    else
      sender.handle(self, MKUINT(ID_UNCHECK, SEL_COMMAND), nil)
    end
    return 1
  end


  # Toggle strip spaces mode
  def onCmdStripSpaces(sender, sel, ptr)
    @stripsp = !@stripsp
    return 1
  end


  # Update toggle strip spaces mode
  def onUpdStripSpaces(sender, sel, ptr)
    if @stripsp
      sender.handle(self, MKUINT(ID_CHECK, SEL_COMMAND), nil)
    else
      sender.handle(self, MKUINT(ID_UNCHECK, SEL_COMMAND), nil)
    end
    return 1
  end


  # Reopen file
  def onCmdReopen(sender, sel, ptr)
    if !@undolist.marked?
      if FXMessageBox.question(self, MBOX_YES_NO, "Document was changed",
        "Discard changes to this document?") == MBOX_CLICKED_NO
           return 1
      end
    end
    loadFile(@filename)
    return 1
  end


  # Update reopen file