Advertisement
edile

Edile Text Editor v0.2

Oct 15th, 2012
208
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 95.67 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. ########################################################################
  4. # This program is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 2 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. #
  18. # -----------------------------------------------------------------------------
  19. #
  20. # This is Edile: A PyGTK+ text editor.
  21. # http://edile.googlecode.com -> https://bitbucket.org/edile
  22.  
  23. # Edile is a basic but useful text editor implemented in one source code file.
  24. # It requires only PyGTK but if you have pygtksourceview2 installed it will use that.
  25. #
  26. # This file is based on part of the tutorial: Linux GUI Programming with GTK+ and Glade3
  27. # http://www.micahcarrick.com/12-24-2007/gtk-glade-tutorial-part-1.html
  28. ########################################################################
  29.  
  30. # edit default configuration here
  31. #=======================================================================
  32.  
  33. CONF_FONT                           =       "inconsolata 10"
  34. CONF_HIGHLIGHT_CURRENT_LINE         =       True
  35. CONF_HIGHLIGHT_MATCHING_BRACKETS    =       True
  36. CONF_OVERWRITE                      =       False              # insert/overwrite mode
  37. CONF_SHOW_LINE_NUMBERS              =       True
  38. CONF_AUTO_INDENT                    =       True
  39. CONF_INDENT_ON_TAB                  =       True
  40. CONF_SHOW_RIGHT_MARGIN              =       True
  41. CONF_RIGHT_MARGIN_POSITION          =       72
  42. CONF_HIGHLIGHT_SYNTAX               =       True
  43. CONF_SPACES_INSTEAD_OF_TABS         =       True
  44. CONF_TAB_WIDTH                      =       4
  45. CONF_INDENT_WIDTH                   =       -1                  # -1 means use same as tab width
  46. CONF_MAX_UNDO_LEVELS                =       50                  # -1 means no limit
  47.  
  48. CONF_HIGHLIGHT_CHANGES_SINCE_SAVE   =       True
  49.  
  50. # color for highlighting changes since last save
  51. CONF_CHANGE_HIGHLIGHT               =       "dark slate gray"      # from /etc/X11/rgb.txt
  52.  
  53. # color for highlighting find/replace matches
  54. CONF_FIND_HIGHLIGHT                 =       "IndianRed4"
  55.  
  56. # gtksrcview color scheme
  57. CONF_STYLE_SCHEME                   =       ("oblivion","kate","tango","classic")
  58.  
  59. # 'note pad'. will open this file on startup instead of untitled. empty string means no default file.
  60. CONF_DEFAULT_FILE                   =       ""
  61.  
  62. # whether or not to load plugins. off by default.
  63. # plugins provide a way for you to customise edile for your purpose or environment
  64. # without changing the application's source code.
  65. CONF_LOAD_PLUGINS                   =       False
  66.  
  67. # whether to load plugins when running as the super user. 'no' by default.
  68. CONF_LOAD_PLUGINS_AS_ROOT           =       False
  69.  
  70. # url of file to load plugins from. any scheme should work (e.g. file:///, http://)
  71. # default is http://edile.googlecode.com/files/edile_plugins-0.1.8.py
  72. # see that file for a description of the plugin interface.
  73. # as of version 0.1.8 options can also be set from that file.
  74. CONF_PLUGIN_LOCATION             =       "http://edile.googlecode.com/files/edile_plugins-0.1.7.py"
  75. # sha 256 hash of the plugin file for authentication. empty string means no authentication.
  76. CONF_PLUGIN_SHA256               =       "eca99d7b7ae2042a742366d7b389857d7fa2ee496573d7dee4ebb5a885b53288"
  77.  
  78. # move whichever you want as default into the first position
  79. CONF_WRAP                           =   ('None','Character','Word')
  80. CONF_SMART_HOME_END_TYPE            =   ('Before','Disabled','After','Always')
  81.  
  82. #=======================================================================
  83. # end configuration
  84.  
  85. # stuff here you probably shouldn't edit
  86. #=======================================================================
  87. EDILE_VERSION = '0.2'
  88. EDILE_URL = 'http://edile.googlecode.com'
  89. EDILE_NAME = 'Edile'
  90. EDILE_DESCRIPTION = 'a pygtk text editor in one file.'
  91. #=======================================================================
  92.  
  93. # here begins the program edile
  94.  
  95. # TODO: command line options (verbosity, language, conf options)
  96. #       improve find code. handle everything internal to edile w/o relying on gtksrcview features eg. case sensitivity
  97. #       config option for encoding to use when saving file instead of always file's encoding
  98. #       generally firm everything up. condense and refactor code, exception handling, etc.
  99.  
  100. # UI definition. GTK builder XML string
  101. U_I = '''
  102. <?xml version="1.0"?>
  103. <interface>
  104.  <object class="GtkUIManager" id="uimanager1">
  105.    <child>
  106.      <object class="GtkActionGroup" id="actiongroup1">
  107.        <child>
  108.          <object class="GtkAction" id="file_menu">
  109.            <property name="name">file_menu</property>
  110.            <property name="label" translatable="yes">_File</property>
  111.          </object>
  112.        </child>
  113.        <child>
  114.          <object class="GtkAction" id="new_menu_item">
  115.            <property name="stock_id">gtk-new</property>
  116.            <property name="name">new_menu_item</property>
  117.            <property name="label" translatable="yes">_New</property>
  118.            <signal handler="on_new_menu_item_activate" name="activate"/>
  119.          </object>
  120.        </child>
  121.        <child>
  122.          <object class="GtkAction" id="new_window_menu_item">
  123.            <property name="stock_id">gtk-new</property>
  124.            <property name="name">new_window_menu_item</property>
  125.            <property name="label" translatable="yes">N_ew Window</property>
  126.            <signal handler="on_new_window_menu_item_activate" name="activate"/>
  127.          </object>
  128.          <accelerator key="N" modifiers="GDK_CONTROL_MASK|GDK_SHIFT_MASK"/>
  129.        </child>
  130.        <child>
  131.          <object class="GtkAction" id="open_menu_item">
  132.            <property name="stock_id">gtk-open</property>
  133.            <property name="name">open_menu_item</property>
  134.            <property name="label" translatable="yes">_Open</property>
  135.            <signal handler="on_open_menu_item_activate" name="activate"/>
  136.          </object>
  137.        </child>
  138.         <child>
  139.          <object class="GtkAction" id="open_in_new_window_menu_item">
  140.            <property name="stock_id">gtk-open</property>
  141.            <property name="name">open_in_new_window_menu_item</property>
  142.            <property name="label" translatable="yes">Open _In New Window</property>
  143.            <signal handler="on_open_in_new_window_menu_item_activate" name="activate"/>
  144.          </object>
  145.          <accelerator key="O" modifiers="GDK_CONTROL_MASK|GDK_SHIFT_MASK"/>
  146.        </child>
  147.       <child>
  148.          <object class="GtkAction" id="save_menu_item">
  149.            <property name="stock_id">gtk-save</property>
  150.            <property name="name">save_menu_item</property>
  151.            <property name="label" translatable="yes">_Save</property>
  152.            <signal handler="on_save_menu_item_activate" name="activate"/>
  153.          </object>
  154.        </child>
  155.        <child>
  156.          <object class="GtkAction" id="save_as_menu_item">
  157.            <property name="stock_id">gtk-save-as</property>
  158.            <property name="name">save_as_menu_item</property>
  159.            <property name="label" translatable="yes">Save _As</property>
  160.            <signal handler="on_save_as_menu_item_activate" name="activate"/>
  161.          </object>
  162.        </child>
  163.        <child>
  164.          <object class="GtkAction" id="reload_menu_item">
  165.            <property name="stock_id">gtk-reload</property>
  166.            <property name="name">reload_menu_item</property>
  167.            <property name="label" translatable="yes">Reload</property>
  168.            <signal handler="on_reload_menu_item_activate" name="activate"/>
  169.          </object>
  170.        </child>
  171.        <child>
  172.          <object class="GtkAction" id="execute_menu_item">
  173.            <property name="stock_id">gtk-execute</property>
  174.            <property name="name">execute_menu_item</property>
  175.            <property name="label" translatable="yes">_Run In Terminal</property>
  176.            <signal handler="on_execute_menu_item_activate" name="activate"/>
  177.          </object>
  178.          <accelerator key="R" modifiers="GDK_CONTROL_MASK"/>
  179.        </child>
  180.        <child>
  181.          <object class="GtkAction" id="close_menu_item">
  182.            <property name="stock_id">gtk-close</property>
  183.            <property name="name">close_menu_item</property>
  184.            <property name="label" translatable="yes">_Close</property>
  185.            <signal handler="on_close_menu_item_activate" name="activate"/>
  186.          </object>
  187.        </child>
  188.        <child>
  189.          <object class="GtkAction" id="quit_menu_item">
  190.            <property name="stock_id">gtk-quit</property>
  191.            <property name="name">quit_menu_item</property>
  192.            <property name="label" translatable="yes">_Quit</property>
  193.            <signal handler="on_quit_menu_item_activate" name="activate"/>
  194.          </object>
  195.        </child>
  196.        <child>
  197.          <object class="GtkAction" id="edit_menu">
  198.            <property name="name">edit_menu</property>
  199.            <property name="label" translatable="yes">_Edit</property>
  200.          </object>
  201.        </child>
  202.        <child>
  203.          <object class="GtkAction" id="undo_menu_item">
  204.            <property name="stock_id">gtk-undo</property>
  205.            <property name="name">undo_menu_item</property>
  206.            <property name="label" translatable="yes">_Undo</property>
  207.            <signal handler="on_undo_menu_item_activate" name="activate"/>
  208.          </object>
  209.        <accelerator key="Z" modifiers="GDK_CONTROL_MASK"/>
  210.        </child>
  211.        <child>
  212.          <object class="GtkAction" id="redo_menu_item">
  213.            <property name="stock_id">gtk-redo</property>
  214.            <property name="name">redo_menu_item</property>
  215.            <property name="label" translatable="yes">_Redo</property>
  216.            <signal handler="on_redo_menu_item_activate" name="activate"/>
  217.          </object>
  218.        <accelerator key="Z" modifiers="GDK_CONTROL_MASK|GDK_SHIFT_MASK"/>
  219.        </child>
  220.        <child>
  221.          <object class="GtkAction" id="cut_menu_item">
  222.            <property name="stock_id">gtk-cut</property>
  223.            <property name="name">cut_menu_item</property>
  224.            <property name="label" translatable="yes">Cu_t</property>
  225.            <signal handler="on_cut_menu_item_activate" name="activate"/>
  226.          </object>
  227.        </child>
  228.        <child>
  229.          <object class="GtkAction" id="copy_menu_item">
  230.            <property name="stock_id">gtk-copy</property>
  231.            <property name="name">copy_menu_item</property>
  232.            <property name="label" translatable="yes">_Copy</property>
  233.            <signal handler="on_copy_menu_item_activate" name="activate"/>
  234.          </object>
  235.        </child>
  236.        <child>
  237.          <object class="GtkAction" id="paste_menu_item">
  238.            <property name="stock_id">gtk-paste</property>
  239.            <property name="name">paste_menu_item</property>
  240.            <property name="label" translatable="yes">_Paste</property>
  241.            <signal handler="on_paste_menu_item_activate" name="activate"/>
  242.          </object>
  243.        </child>
  244.        <child>
  245.          <object class="GtkAction" id="select_all_menu_item">
  246.            <property name="stock_id">gtk-select-all</property>
  247.            <property name="name">select_all_menu_item</property>
  248.            <property name="label" translatable="yes">Select _All</property>
  249.            <signal handler="on_select_all_menu_item_activate" name="activate"/>
  250.          </object>
  251.        <accelerator key="A" modifiers="GDK_CONTROL_MASK"/>
  252.        </child>
  253.        <child>
  254.          <object class="GtkAction" id="delete_menu_item">
  255.            <property name="stock_id">gtk-delete</property>
  256.            <property name="name">delete_menu_item</property>
  257.            <property name="label" translatable="yes">_Delete</property>
  258.            <signal handler="on_delete_menu_item_activate" name="activate"/>
  259.          </object>
  260.        </child>
  261.         <child>
  262.          <object class="GtkAction" id="search_menu">
  263.            <property name="name">search_menu</property>
  264.            <property name="label" translatable="yes">_Search</property>
  265.          </object>
  266.        </child>
  267.        <child>
  268.          <object class="GtkAction" id="find_prev_selected_menu_item">
  269.            <property name="name">find_prev_selected_menu_item</property>
  270.            <property name="label" translatable="yes">Find Previous Selected</property>
  271.            <signal handler="on_find_prev_selected_menu_item_activate" name="activate"/>
  272.          </object>
  273.        <accelerator key="E" modifiers="GDK_CONTROL_MASK"/>
  274.        </child>
  275.        <child>
  276.          <object class="GtkAction" id="find_next_selected_menu_item">
  277.            <property name="name">find_next_selected_menu_item</property>
  278.            <property name="label" translatable="yes">Find Next Selected</property>
  279.            <signal handler="on_find_next_selected_menu_item_activate" name="activate"/>
  280.          </object>
  281.        <accelerator key="D" modifiers="GDK_CONTROL_MASK"/>
  282.        </child>
  283.        <child>
  284.          <object class="GtkAction" id="show_find_menu_item">
  285.            <property name="stock_id">gtk-find</property>
  286.            <property name="name">show_find_menu_item</property>
  287.            <property name="label" translatable="yes">_Find &amp; Replace</property>
  288.            <signal handler="on_show_find_menu_item_activate" name="activate"/>
  289.          </object>
  290.        <accelerator key="F" modifiers="GDK_CONTROL_MASK"/>
  291.        </child>
  292.        <child>
  293.          <object class="GtkAction" id="find_next_menu_item">
  294.            <property name="stock_id">gtk-go-forward</property>
  295.            <property name="name">find_next_menu_item</property>
  296.            <property name="label" translatable="yes">Find _Next</property>
  297.            <signal handler="on_find_next_menu_item_activate" name="activate"/>
  298.          </object>
  299.        <accelerator key="G" modifiers="GDK_CONTROL_MASK"/>
  300.        </child>
  301.        <child>
  302.          <object class="GtkAction" id="find_previous_menu_item">
  303.            <property name="stock_id">gtk-go-back</property>
  304.            <property name="name">find_previous_menu_item</property>
  305.            <property name="label" translatable="yes">Find _Previous</property>
  306.            <signal handler="on_find_previous_menu_item_activate" name="activate"/>
  307.          </object>
  308.          <accelerator key="G" modifiers="GDK_CONTROL_MASK|GDK_SHIFT_MASK"/>
  309.        </child>
  310.        <child>
  311.          <object class="GtkAction" id="find_all_menu_item">
  312.            <property name="name">find_all_menu_item</property>
  313.            <property name="label" translatable="yes">Find All</property>
  314.            <signal handler="on_find_all_menu_item_activate" name="activate"/>
  315.          </object>
  316.          <!--<accelerator key="F" modifiers="GDK_CONTROL_MASK|GDK_SHIFT_MASK"/>-->
  317.        </child>
  318.        <!-- <child>
  319.          <object class="GtkAction" id="replace_next_menu_item">
  320.          <property name="stock_id">gtk-find-and-replace</property>
  321.           <property name="name">replace_next_menu_item</property>
  322.            <property name="label" translatable="yes">Replace Next</property>
  323.            <signal handler="on_replace_next_menu_item_activate" name="activate"/>
  324.          </object>
  325.          <accelerator key="G" modifiers="GDK_CONTROL_MASK|GDK_SHIFT_MASK|GDK_MOD1_MASK"/>
  326.        </child> -->
  327.        <child>
  328.          <object class="GtkAction" id="replace_all_menu_item">
  329.            <property name="name">replace_all_menu_item</property>
  330.            <property name="label" translatable="yes">Replace All</property>
  331.            <signal handler="on_replace_all_menu_item_activate" name="activate"/>
  332.          </object>
  333.        </child>
  334.       <child>
  335.          <object class="GtkAction" id="view_menu">
  336.            <property name="name">view_menu</property>
  337.            <property name="label" translatable="yes">_View</property>
  338.          </object>
  339.        </child>
  340.       <child>
  341.          <object class="GtkAction" id="wrap_menu">
  342.            <property name="name">wrap_menu</property>
  343.            <property name="label" translatable="yes">W_rap</property>
  344.          </object>
  345.        </child>
  346.        <child>
  347.          <object class="GtkRadioAction" id="wrap_none_menu_item">
  348.            <property name="name">wrap_none_menu_item</property>
  349.            <property name="label" translatable="yes">_None</property>
  350.            <!--<property name="group">wrap_none_menu_item</property>-->
  351.            <signal handler="on_wrap_none_menu_item_activate" name="activate"/>
  352.          </object>
  353.        </child>
  354.        <child>
  355.          <object class="GtkRadioAction" id="wrap_char_menu_item">
  356.            <property name="name">wrap_char_menu_item</property>
  357.            <property name="label" translatable="yes">_Character</property>
  358.            <property name="group">wrap_none_menu_item</property>
  359.            <signal handler="on_wrap_char_menu_item_activate" name="activate"/>
  360.          </object>
  361.        </child>
  362.        <child>
  363.          <object class="GtkRadioAction" id="wrap_word_menu_item">
  364.            <property name="name">wrap_word_menu_item</property>
  365.            <property name="label" translatable="yes">_Word</property>
  366.            <property name="group">wrap_none_menu_item</property>
  367.            <signal handler="on_wrap_word_menu_item_activate" name="activate"/>
  368.          </object>
  369.        </child>
  370.        <child>
  371.          <object class="GtkAction" id="select_font_menu_item">
  372.            <property name="name">select_font_menu_item</property>
  373.            <property name="label" translatable="yes">Select Font...</property>
  374.            <signal handler="on_select_font_menu_item_activate" name="activate"/>
  375.          </object>
  376.        </child>
  377.        <child>
  378.          <object class="GtkAction" id="help_menu">
  379.            <property name="name">help_menu</property>
  380.            <property name="label" translatable="yes">_Help</property>
  381.          </object>
  382.        </child>
  383.         <child>
  384.          <object class="GtkAction" id="view_source_menu_item">
  385.            <!--<property name="stock_id">gtk-help</property>-->
  386.            <property name="name">view_source_menu_item</property>
  387.            <property name="label" translatable="yes">_View Source</property>
  388.            <signal handler="on_view_source_menu_item_activate" name="activate"/>
  389.          </object>
  390.          <!--<accelerator key="" modifiers=""/>-->
  391.        </child>
  392.       <child>
  393.          <object class="GtkAction" id="about_menu_item">
  394.            <property name="stock_id">gtk-about</property>
  395.            <property name="name">about_menu_item</property>
  396.            <property name="label" translatable="yes">_About</property>
  397.            <signal handler="on_about_menu_item_activate" name="activate"/>
  398.          </object>
  399.        </child>
  400.      </object>
  401.    </child>
  402.    <ui>
  403.      <menubar name="menubar1">
  404.        <menu action="file_menu">
  405.          <menuitem action="new_menu_item"/>
  406.          <menuitem action="new_window_menu_item"/>
  407.          <separator/>
  408.          <menuitem action="open_menu_item"/>
  409.          <menuitem action="open_in_new_window_menu_item"/>
  410.          <separator/>
  411.          <menuitem action="save_menu_item"/>
  412.          <menuitem action="save_as_menu_item"/>
  413.          <separator/>
  414.          <menuitem action="reload_menu_item"/>
  415.          <menuitem action="execute_menu_item"/>
  416.          <separator/>
  417.          <menuitem action="close_menu_item"/>
  418.          <menuitem action="quit_menu_item"/>
  419.        </menu>
  420.        <menu action="edit_menu">
  421.          <menuitem action="undo_menu_item"/>
  422.          <menuitem action="redo_menu_item"/>
  423.          <separator/>
  424.          <menuitem action="cut_menu_item"/>
  425.          <menuitem action="copy_menu_item"/>
  426.          <menuitem action="paste_menu_item"/>
  427.          <menuitem action="select_all_menu_item"/>
  428.          <separator/>
  429.          <menuitem action="delete_menu_item"/>
  430.        </menu>
  431.        <menu action="search_menu">
  432.          <menuitem action="find_prev_selected_menu_item"/>
  433.          <menuitem action="find_next_selected_menu_item"/>
  434.          <separator/>
  435.          <menuitem action="show_find_menu_item"/>
  436.          <menuitem action="find_next_menu_item"/>
  437.          <menuitem action="find_previous_menu_item"/>
  438.          <menuitem action="find_all_menu_item"/>
  439.          <separator/>
  440.          <!--<menuitem action="replace_next_menu_item"/>-->
  441.          <menuitem action="replace_all_menu_item"/>
  442.        </menu>
  443.        <menu action="view_menu">
  444.          <menu action="wrap_menu">
  445.          <menuitem action="wrap_none_menu_item"/>
  446.          <menuitem action="wrap_char_menu_item"/>
  447.          <menuitem action="wrap_word_menu_item"/>
  448.          </menu>
  449.          <separator/>
  450.          <menuitem action="select_font_menu_item"/>
  451.        </menu>
  452.        <menu action="help_menu">
  453.          <menuitem action="view_source_menu_item"/>
  454.          <menuitem action="about_menu_item"/>
  455.        </menu>
  456.      </menubar>
  457.    </ui>
  458.  </object>
  459.  <object class="GtkWindow" id="window">
  460.    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
  461.    <property name="title" translatable="yes">Edile Text Editor</property>
  462.    <property name="default_width">540</property>
  463.    <property name="default_height">660</property>
  464.    <signal handler="on_window_destroy" name="destroy"/>
  465.    <signal handler="on_window_delete_event" name="delete_event"/>
  466.    <child>
  467.      <object class="GtkVBox" id="vbox1">
  468.        <property name="visible">True</property>
  469.        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
  470.        <child>
  471.          <object class="GtkMenuBar" constructor="uimanager1" id="menubar1">
  472.            <property name="visible">True</property>
  473.            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
  474.          </object>
  475.          <packing>
  476.            <property name="expand">False</property>
  477.          </packing>
  478.        </child>
  479.        <child>
  480.          <object class="GtkScrolledWindow" id="scrolledwindow">
  481.            <property name="visible">True</property>
  482.            <property name="can_focus">True</property>
  483.            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
  484.            <property name="border_width">0</property>
  485.            <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
  486.            <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
  487.            <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
  488.            <child>
  489.                <object class="GtkTextView" id="text_view">
  490.                <property name="visible">True</property>
  491.                <property name="can_focus">True</property>
  492.                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
  493.                <property name="left_margin">2</property>
  494.                <property name="right_margin">2</property>
  495.                <property name="wrap_mode">GTK_WRAP_NONE</property>
  496.                <!--<signal handler="on_text_view_insert_at_cursor" name="insert-at-cursor"/>-->
  497.                <!--<signal name="drag_data_received" handler="on_log_drag_data_received"/>-->
  498.              </object>
  499.            </child>
  500.          </object>
  501.          <packing>
  502.            <property name="position">1</property>
  503.          </packing>
  504.        </child>
  505.        <child>
  506.          <object class="GtkStatusbar" id="statusbar">
  507.            <property name="visible">True</property>
  508.            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
  509.            <property name="spacing">2</property>
  510.          </object>
  511.          <packing>
  512.            <property name="expand">False</property>
  513.            <property name="position">2</property>
  514.          </packing>
  515.        </child>
  516.      </object>
  517.    </child>
  518.  </object>
  519. </interface>
  520. '''
  521.  
  522. # for the search ui, because it was easier this way.
  523. SEARCH_UI = '''
  524. <?xml version="1.0"?>
  525. <interface>
  526. <!-- search ui -->
  527. <object class="GtkWindow" id="search_window">
  528.    <signal handler="on_search_window_delete_event" name="delete_event"/>
  529.    <property name="skip-taskbar-hint">True</property>
  530.  
  531. <child>
  532.      <object class="GtkVBox" id="vbox9">
  533.  
  534.  
  535.        <property name="visible">True</property>
  536.        <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
  537.        <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
  538.        <child>
  539.          <object class="GtkHBox" id="hbox1">
  540.            <property name="visible">True</property>
  541.            <child>
  542.              <object class="GtkLabel" id="label1">
  543.                <property name="visible">True</property>
  544.                <property name="label" translatable="yes">Find</property>
  545.                <property name="justify">GTK_JUSTIFY_RIGHT</property>
  546.              </object>
  547.            </child>
  548.            <child>
  549.              <object class="GtkEntry" id="search_find_field">
  550.                <property name="visible">True</property>
  551.                <property name="can_focus">True</property>
  552.                <property name="invisible_char">&#x25CF;</property>
  553.                <signal handler="search_find_field_changed" name="changed"/>
  554.              </object>
  555.              <packing>
  556.                <property name="position">1</property>
  557.              </packing>
  558.            </child>
  559.          </object>
  560.        </child>
  561.        <child>
  562.          <object class="GtkHBox" id="hbox2">
  563.            <property name="visible">True</property>
  564.            <child>
  565.              <object class="GtkLabel" id="label2">
  566.                <property name="visible">True</property>
  567.                <property name="label" translatable="yes">Replace</property>
  568.                <property name="justify">GTK_JUSTIFY_RIGHT</property>
  569.              </object>
  570.            </child>
  571.            <child>
  572.              <object class="GtkEntry" id="search_replace_field">
  573.                <property name="visible">True</property>
  574.                <property name="can_focus">True</property>
  575.                <property name="invisible_char">&#x25CF;</property>
  576.                <signal handler="search_replace_field_changed" name="changed"/>
  577.              </object>
  578.              <packing>
  579.                <property name="position">1</property>
  580.              </packing>
  581.            </child>
  582.          </object>
  583.          <packing>
  584.            <property name="position">1</property>
  585.          </packing>
  586.        </child>
  587.        <child>
  588.          <object class="GtkCheckButton" id="search_whole_word_checkbox">
  589.            <property name="visible">True</property>
  590.            <property name="can_focus">True</property>
  591.            <property name="label" translatable="yes">Whole word</property>
  592.            <property name="draw_indicator">True</property>
  593.            <signal handler="on_search_whole_word_checkbox_toggled" name="toggled"/>
  594.          </object>
  595.          <packing>
  596.            <property name="position">2</property>
  597.          </packing>
  598.        </child>
  599.        <child>
  600.          <object class="GtkCheckButton" id="search_case_sensitive_checkbox">
  601.            <property name="visible">True</property>
  602.            <property name="can_focus">True</property>
  603.            <property name="label" translatable="yes">Case sensitive</property>
  604.            <property name="draw_indicator">True</property>
  605.            <!--<property name="active">True</property>-->
  606.            <signal handler="on_search_case_sensitive_checkbox_toggled" name="toggled"/>
  607.         </object>
  608.          <packing>
  609.            <property name="position">3</property>
  610.          </packing>
  611.        </child>
  612.        <child>
  613.          <object class="GtkHSeparator" id="hseparator1">
  614.            <property name="visible">True</property>
  615.          </object>
  616.          <packing>
  617.            <property name="expand">False</property>
  618.            <property name="position">4</property>
  619.          </packing>
  620.        </child>
  621.        <child>
  622.          <object class="GtkHBox" id="hbox3">
  623.            <property name="visible">True</property>
  624.            <child>
  625.              <object class="GtkButton" id="search_close_button">
  626.                <property name="visible">True</property>
  627.                <property name="can_focus">True</property>
  628.                <property name="receives_default">True</property>
  629.                <property name="label" translatable="yes">Close</property>
  630.                <signal handler="on_search_window_delete_event" name="clicked"/>
  631.              </object>
  632.            </child>
  633.            <child>
  634.              <object class="GtkButton" id="search_find_previous_button">
  635.                <property name="visible">True</property>
  636.                <property name="can_focus">True</property>
  637.                <property name="receives_default">True</property>
  638.                <property name="label" translatable="yes">Find Previous</property>
  639.                <signal handler="on_find_previous_menu_item_activate" name="clicked"/>
  640.              </object>
  641.              <packing>
  642.                <property name="position">1</property>
  643.              </packing>
  644.            </child>
  645.            <child>
  646.              <object class="GtkButton" id="search_find_next_button">
  647.                <property name="visible">True</property>
  648.                <property name="can_focus">True</property>
  649.                <property name="receives_default">True</property>
  650.                <property name="label" translatable="yes">Find Next</property>
  651.                <signal handler="on_find_next_menu_item_activate" name="clicked"/>
  652.              </object>
  653.              <packing>
  654.                <property name="position">2</property>
  655.              </packing>
  656.            </child>
  657.            <child>
  658.              <object class="GtkButton" id="search_replace_and_find_button">
  659.                <property name="visible">True</property>
  660.                <property name="can_focus">True</property>
  661.                <property name="receives_default">True</property>
  662.                <property name="label" translatable="yes">Find &amp; Replace</property>
  663.                <signal handler="on_replace_and_find_menu_item_activate" name="clicked"/>
  664.              </object>
  665.              <packing>
  666.                <property name="position">3</property>
  667.              </packing>
  668.            </child>
  669.          </object>
  670.          <packing>
  671.            <property name="position">5</property>
  672.          </packing>
  673.        </child>
  674.      </object>
  675.      </child>
  676.      </object>
  677. </interface>
  678. '''
  679.  
  680.  
  681.  
  682. import sys
  683. import os
  684. import imp,types,tempfile
  685. import string
  686. #import urlparse
  687. import urllib
  688. #import platform
  689. import gio #this breaks windows
  690. import gtk,gobject
  691. import pango
  692. import subprocess
  693. import hashlib
  694.  
  695. from optparse import OptionParser
  696.  
  697.  
  698. # prints about info from global vars to console
  699. def print_about():
  700.     print "\n%s %s\n%s\n%s"%(EDILE_NAME,EDILE_VERSION,EDILE_URL,EDILE_DESCRIPTION)
  701.  
  702. print_about()
  703.  
  704. try:
  705.     import gtksourceview2
  706.     using_source_view = True
  707.     print "using gtksourceview"
  708. except ImportError:
  709.     using_source_view = False
  710.     print "not using gtksourceview"
  711.     pass
  712.  
  713.  
  714.  
  715. # names for text wrapping types
  716. CONF_WRAP_MAP = {'None':gtk.WRAP_NONE,'Character':gtk.WRAP_CHAR, 'Word':gtk.WRAP_WORD, 'Word Character':gtk.WRAP_WORD_CHAR}
  717.  
  718. if using_source_view:
  719.     # names for gtksourceview smart home end types
  720.     CONF_SMART_HOME_END_TYPE_MAP =  {'Disabled':gtksourceview2.SMART_HOME_END_DISABLED,'Before':gtksourceview2.SMART_HOME_END_BEFORE,'After':gtksourceview2.SMART_HOME_END_AFTER,'Always':gtksourceview2.SMART_HOME_END_ALWAYS}
  721.  
  722. class Edile:
  723.  
  724. ###
  725. # on_* = action methods from ui
  726. ###
  727.  
  728.     # Called when the user clicks the 'About' menu. We use gtk_show_about_dialog()
  729.     # which is a convenience function to show a GtkAboutDialog. This dialog will
  730.     # NOT be modal but will be on top of the main application window.
  731.     def on_about_menu_item_activate(self, menuitem, data=None):
  732.  
  733.         # show standard gtk about window
  734.         def show_about():
  735.             if self.about_dialog:
  736.                 self.about_dialog.present()
  737.                 return
  738.  
  739.  
  740.             about_dialog = gtk.AboutDialog()
  741.             about_dialog.set_transient_for(self.window)
  742.             about_dialog.set_destroy_with_parent(True)
  743.             about_dialog.set_name(EDILE_NAME)
  744.             about_dialog.set_version(EDILE_VERSION)
  745.             about_dialog.set_copyright("")
  746.             about_dialog.set_website(EDILE_URL)
  747.             about_dialog.set_comments(EDILE_DESCRIPTION)
  748.             #about_dialog.set_authors(EDILE_AUTHORS)
  749.             about_dialog.set_logo_icon_name(gtk.STOCK_EDIT)
  750.  
  751.             # callbacks for destroying the about dialog
  752.             def close(dialog, response, editor):
  753.                 editor.about_dialog = None
  754.                 dialog.destroy()
  755.  
  756.             def delete_event(dialog, event, editor):
  757.                 editor.about_dialog = None
  758.                 return True
  759.  
  760.             about_dialog.connect("response", close, self)
  761.             about_dialog.connect("delete-event", delete_event, self)
  762.  
  763.             self.about_dialog = about_dialog
  764.             about_dialog.show()
  765.  
  766.         # run functions
  767.         print_about()
  768.         show_about()
  769.  
  770.     # view source. displays this file in a new instance.
  771.     def on_view_source_menu_item_activate(self, menuitem, data=None):
  772.         exe = __file__
  773.         exepath = os.path.realpath(exe)
  774.         self.spawn(exepath)
  775.  
  776.     # tries to run file in a terminal
  777.     def on_execute_menu_item_activate(self,menuitem,data=None):
  778.         exe = self.filename
  779.  
  780.         if exe == None:
  781.             self.error_message("Save file first!")
  782.             return
  783.  
  784.         if os.path.exists(exe):
  785.             exepath = os.path.realpath(exe)
  786.             subprocess.Popen(["xterm", "-hold", "-e", "\"%s\""%(exepath)])
  787.  
  788.  
  789.     # When our window is destroyed, we want to break out of the GTK main loop.
  790.     # We do this by calling gtk_main_quit(). We could have also just specified
  791.     # gtk_main_quit as the handler in Glade!
  792.     def on_window_destroy(self, widget, data=None):
  793.         gtk.main_quit()
  794.  
  795.     # When the window is requested to be closed, we need to check if they have
  796.     # unsaved work. We use this callback to prompt the user to save their work
  797.     # before they exit the application. From the "delete-event" signal, we can
  798.     # choose to effectively cancel the close based on the value we return.
  799.     def on_window_delete_event(self, widget, event, data=None):
  800.         if self.check_for_save():
  801.             self.on_save_menu_item_activate(None, None)
  802.             # if user cancelled save
  803.             if self.filename == None: return True
  804.  
  805.         self.log('exiting')
  806.         return False # Propogate event
  807.  
  808.     # Called when the user clicks the 'New' menu. We need to prompt for save if
  809.     # the file has been modified, and then delete the buffer and clear the
  810.     # modified flag.
  811.     def on_new_menu_item_activate(self, menuitem, data=None):
  812.         if self.check_for_save(): self.on_save_menu_item_activate(None, None)
  813.  
  814.         # clear editor for a new file
  815.         buff = self.text_view.get_buffer()
  816.         buff.set_text("")
  817.         buff.set_modified(False)
  818.         self.filename = None
  819.     self.language = None
  820.     self.text_encoding = None
  821.         self.reset_default_status()
  822.  
  823.     def on_new_window_menu_item_activate(self, menuitem, data=None):
  824.         self.spawn()
  825.  
  826.     # Called when the user clicks the 'Open' menu. We need to prompt for save if
  827.     # thefile has been modified, allow the user to choose a file to open, and
  828.     # then call load_file() on that file.
  829.     def on_open_menu_item_activate(self, menuitem, data=None):
  830.         if self.check_for_save(): self.on_save_menu_item_activate(None, None)
  831.  
  832.         filename = self.get_open_filename()
  833.         if filename: self.load_file(filename)
  834.  
  835.     def on_open_in_new_window_menu_item_activate(self, menuitem, data=None):
  836.         filename = self.get_open_filename()
  837.         if filename: self.spawn(filename)
  838.  
  839.  
  840.     # Called when the user clicks the 'Save' menu. We need to allow the user to choose
  841.     # a file to save if it's an untitled document, and then call write_file() on that
  842.     # file.
  843.     def on_save_menu_item_activate(self, menuitem, data=None):
  844.         if self.filename == None:
  845.             filename = self.get_save_filename()
  846.             if filename: self.write_file(filename)
  847.         else: self.write_file(None)
  848.  
  849.     # Called when the user clicks the 'Save As' menu. We need to allow the user
  850.     # to choose a file to save and then call write_file() on that file.
  851.     def on_save_as_menu_item_activate(self, menuitem, data=None):
  852.         filename = self.get_save_filename()
  853.         if filename: self.write_file(filename)
  854.  
  855.     def on_close_menu_item_activate(self, menuitem, data=None):
  856.         if self.check_for_save():
  857.             self.on_save_menu_item_activate(None, None)
  858.             # if user cancelled save
  859.             if self.filename == None: return
  860.         self.text_view.set_sensitive(False)
  861.         buff = self.text_view.get_buffer()
  862.         buff.set_text("")
  863.         buff.set_modified(False)
  864.         self.text_view.set_sensitive(True)
  865.         self.filename = None
  866.         self.language = None
  867.         self.reset_default_status()
  868.  
  869.     # Offer to save any changes, then reload original file from disk
  870.     def on_reload_menu_item_activate(self, menuitem, data=None):
  871.         old_filename = self.filename
  872.         if self.check_for_save():
  873.             self.on_save_as_menu_item_activate(menuitem, None)
  874.             # if user cancelled save
  875.             if self.filename == None: return
  876.  
  877.         self.log('reloading %s'%(old_filename))
  878.         self.load_file(old_filename)
  879.  
  880.     # Called when the user clicks the 'Quit' menu. We need to prompt for save if
  881.     # the file has been modified and then break out of the GTK+ main loop
  882.     def on_quit_menu_item_activate(self, menuitem, data=None):
  883.         if self.check_for_save():
  884.             self.on_save_menu_item_activate(None, None)
  885.             # if user cancelled save
  886.             if self.filename == None: return
  887.  
  888.         self.log('exiting')
  889.         gtk.main_quit()
  890.  
  891.     def on_undo_menu_item_activate(self, menuitem, data=None):
  892.         if using_source_view:
  893.             if self.text_view.get_buffer().can_undo():
  894.                 self.text_view.get_buffer().undo()
  895.  
  896.     def on_redo_menu_item_activate(self, menuitem, data=None):
  897.         if using_source_view:
  898.             if self.text_view.get_buffer().can_redo():
  899.                 self.text_view.get_buffer().redo()
  900.     # Called when the user clicks the 'Cut' menu.
  901.     def on_cut_menu_item_activate(self, menuitem, data=None):
  902.         buff = self.text_view.get_buffer();
  903.         buff.cut_clipboard (gtk.clipboard_get(), True);
  904.  
  905.     # Called when the user clicks the 'Copy' menu.
  906.     def on_copy_menu_item_activate(self, menuitem, data=None):
  907.         buff = self.text_view.get_buffer();
  908.         buff.copy_clipboard (gtk.clipboard_get());
  909.  
  910.     # Called when the user clicks the 'Paste' menu.
  911.     def on_paste_menu_item_activate(self, menuitem, data=None):
  912.         buff = self.text_view.get_buffer();
  913.         buff.paste_clipboard (gtk.clipboard_get(), None, True);
  914.  
  915.     def on_select_all_menu_item_activate(self, menuitem, data=None):
  916.         buff = self.text_view.get_buffer();
  917.         buff.select_range(buff.get_start_iter(),buff.get_end_iter())
  918.  
  919.     # Called when the user clicks the 'Delete' menu.
  920.     def on_delete_menu_item_activate(self, menuitem, data=None):
  921.         buff = self.text_view.get_buffer();
  922.  
  923.  
  924.         gone = buff.get_text(buff.get_selection_bounds()[0],buff.get_selection_bounds()[1])
  925.         self.log('deleting %s'%(gone))
  926.  
  927.         buff.delete_selection (False, True);
  928.  
  929.     def on_find_prev_selected_menu_item_activate(self,menuitem,data=None):
  930.         buff = self.text_view.get_buffer()
  931.         selected = buff.get_text(buff.get_selection_bounds()[0],buff.get_selection_bounds()[1])
  932.  
  933.         iter = self.get_find_iter(buffer=buff, backwards=True,limit_iter=None)
  934.  
  935.         results = self.do_find_with_iter(iter=iter, search_for=selected,backwards=True,case_sensitive=False,whole_word=False)
  936.  
  937.         try:
  938.             buff.select_range(results[0],results[1])
  939.             self.text_view.scroll_to_mark(mark=buff.get_insert(),within_margin=0.33,use_align=True,xalign=0.5,yalign=0.5)
  940.         except:
  941.             self.log("\'%s\' not found."%(selected))
  942.  
  943.     def on_find_next_selected_menu_item_activate(self,menuitem,data=None):
  944.         buff = self.text_view.get_buffer()
  945.         selected = buff.get_text(buff.get_selection_bounds()[0],buff.get_selection_bounds()[1])
  946.  
  947.         iter = self.get_find_iter(buffer=buff, backwards=False,limit_iter=None)
  948.  
  949.         results = self.do_find_with_iter(iter=iter, search_for=selected,backwards=False,case_sensitive=True,whole_word=False)
  950.  
  951.         try:
  952.             buff.select_range(results[0],results[1])
  953.             self.text_view.scroll_to_mark(mark=buff.get_insert(),within_margin=0.33,use_align=True,xalign=0.5,yalign=0.5)
  954.         except:
  955.             self.log("\'%s\' not found."%(selected))
  956.  
  957.     def on_search_case_sensitive_checkbox_toggled(self, data=None):
  958.         #self.search_case_sensitive = togglebutton.get_active()
  959.         self.search_case_sensitive = not self.search_case_sensitive
  960.  
  961.  
  962.     def on_search_whole_word_checkbox_toggled(self, data=None):
  963.         #self.search_is_whole_word = togglebutton.get_active()
  964.         self.search_is_whole_word = not self.search_is_whole_word
  965.  
  966.     def search_find_field_changed(self, data=None):
  967.         self.search_string = self.search_field.get_text()
  968.     def search_replace_field_changed(self, data=None):
  969.         self.replacement_string = self.replace_field.get_text()
  970.  
  971.     def on_show_find_menu_item_activate(self,menuitem,data=None):
  972.         #TODO: could load search UI from xml string here
  973.  
  974.         if self.search_window.get_property("visible"):
  975.             self.search_window.present()
  976.             return
  977.  
  978.         buff = self.text_view.get_buffer()
  979.         if self.search_string == "":
  980.             if buff.get_selection_bounds():
  981.                 self.search_string = buff.get_slice(buff.get_selection_bounds()[0],buff.get_selection_bounds()[1])
  982.  
  983.         self.search_field.set_text(self.search_string)
  984.         self.replace_field.set_text(self.replacement_string)
  985.         self.search_field.grab_focus()
  986.  
  987.         self.search_window.show_all()
  988.  
  989.     def on_search_window_delete_event(self, widget=None, event=None, data=None):
  990.         self.search_window.hide_all()
  991.         return True
  992.  
  993.     def on_find_next_menu_item_activate(self, sender, data=None):
  994.         buff = self.text_view.get_buffer();
  995.         if self.search_string == "":
  996.             if buff.get_selection_bounds():
  997.                 self.search_string = buff.get_slice(buff.get_selection_bounds()[0],buff.get_selection_bounds()[1])
  998.                 self.search_field.set_text(self.search_string)
  999.             else:
  1000.                 self.error_message("Enter the search string first.")
  1001.                 self.on_show_find_menu_item_activate(sender)
  1002.  
  1003.         next_results = self.do_find(buffer=buff,iter=None,backwards=False,case_sensitive=self.search_case_sensitive,whole_word=self.search_is_whole_word)
  1004.  
  1005.         #highlight next results
  1006.         #offer to wrap
  1007.  
  1008.     #find backwards
  1009.     def on_find_previous_menu_item_activate(self, menuitem, data=None):
  1010.         buff = self.text_view.get_buffer();
  1011.         if self.search_string == "":
  1012.             if buff.get_selection_bounds():
  1013.                 self.search_string = buff.get_slice(buff.get_selection_bounds()[0],buff.get_selection_bounds()[1])
  1014.                 self.search_field.set_text(self.search_string)
  1015.             else:
  1016.                 self.error_message("Enter the search string first.")
  1017.                 self.on_show_find_menu_item_activate(menuitem)
  1018.  
  1019.         prev_results = self.do_find(buffer=buff,iter=None,backwards=True,case_sensitive=self.search_case_sensitive,whole_word=self.search_is_whole_word)
  1020.  
  1021.         #highlight prev results
  1022.         #offer to wrap
  1023.  
  1024.     def on_find_all_menu_item_activate(self, menuitem, data=None):
  1025.         buff = self.text_view.get_buffer();
  1026.         if self.search_string == "":
  1027.             if buff.get_selection_bounds():
  1028.                 self.search_string = buff.get_slice(buff.get_selection_bounds()[0],buff.get_selection_bounds()[1])
  1029.                 self.search_field.set_text(self.search_string)
  1030.             else:
  1031.                 self.error_message("Enter the search string first.")
  1032.                 self.on_show_find_menu_item_activate(menuitem)
  1033.                 return
  1034.         self.do_find_all(buffer=buff)
  1035.  
  1036.     def on_replace_and_find_menu_item_activate(self, menuitem, data=None):
  1037.         if self.search_string == "":
  1038.             self.error_message("Enter the search string first.")
  1039.             return
  1040.         if self.replacement_string == '':
  1041.             self.error_message("Enter the replacement string first.")
  1042.             self.on_show_find_menu_item_activate(menuitem)
  1043.             return
  1044.  
  1045.         buff = self.text_view.get_buffer()
  1046.  
  1047.         replace_iter = self.get_find_iter(buffer=buff, backwards=buff.get_has_selection(),limit_iter=None) #LAST
  1048.  
  1049.         next_results = self.do_find(buffer=buff,iter=replace_iter,backwards=False,case_sensitive=self.search_case_sensitive,whole_word=self.search_is_whole_word)
  1050.  
  1051.         if next_results == None:
  1052.             return
  1053.         else:
  1054.             result_iter = next_results[0]
  1055.             #ask for confirm here
  1056.             self.do_replace_next(buffer=buff,iter=result_iter,search_for=self.search_string,replace_with=self.replacement_string,limit=next_results[1])
  1057.  
  1058.     def on_replace_all_menu_item_activate(self, menuitem, data=None):
  1059.         if self.search_string == "":
  1060.             self.error_message("Enter the search string first.")
  1061.             return
  1062.         if self.replacement_string == "":
  1063.             self.error_message("Enter the replacement string first.")
  1064.             return
  1065.  
  1066.         buff = self.text_view.get_buffer()
  1067.         self.do_replace_all(buff,self.search_string,self.replacement_string)
  1068.  
  1069.  
  1070.     # Called when the user clicks an item from the 'Wrap' menu.
  1071.     def on_wrap_none_menu_item_activate(self, menuitem, data=None):
  1072.         self.wrapping = 'None'
  1073.         self.text_view.set_wrap_mode(gtk.WRAP_NONE);
  1074.  
  1075.     def on_wrap_char_menu_item_activate(self, menuitem, data=None):
  1076.         self.wrapping = 'Character'
  1077.         self.text_view.set_wrap_mode(gtk.WRAP_CHAR);
  1078.  
  1079.     def on_wrap_word_menu_item_activate(self, menuitem, data=None):
  1080.         self.wrapping = 'Word'
  1081.         self.text_view.set_wrap_mode(gtk.WRAP_WORD);
  1082.  
  1083.     def on_select_font_menu_item_activate(self,menuitem, data=None):
  1084.         if not self.font_dialog:
  1085.             window = gtk.FontSelectionDialog("Font Selection Dialog")
  1086.             self.font_dialog = window
  1087.  
  1088.             window.set_position(gtk.WIN_POS_MOUSE)
  1089.             window.set_transient_for(self.window)
  1090.             window.connect("destroy", self.font_dialog_destroyed)
  1091.  
  1092.             window.ok_button.connect("clicked", self.font_selection_ok)
  1093.             window.cancel_button.connect_object("clicked", lambda wid: wid.destroy(), self.font_dialog)
  1094.             current_font = self.text_view.get_pango_context().get_font_description().to_string()
  1095.             window.set_font_name(current_font)
  1096.  
  1097.         window = self.font_dialog
  1098.         if not (window.flags() & gtk.VISIBLE):
  1099.             window.show()
  1100.         else:
  1101.             window.destroy()
  1102.             self.font_dialog = None
  1103.  
  1104.     def font_selection_ok(self, button):
  1105.         self.font = self.font_dialog.get_font_name()
  1106.         if self.window:
  1107.             font_desc = pango.FontDescription(self.font)
  1108.             if font_desc:
  1109.                 self.text_view.modify_font(font_desc)
  1110.                 self.font_dialog.destroy()
  1111.     def font_dialog_destroyed(self, data=None):
  1112.         self.font_dialog = None
  1113.  
  1114.     #emitted when the modified flag of the buffer changes
  1115.     def on_text_buffer_modified_changed(self, buff, data=None):
  1116.         self.mark_window_status(self.window,buff.get_modified())
  1117.  
  1118.     #emitted BEFORE the text is actually inserted into the buffer
  1119.     def on_text_buffer_insert_text(self, buff, iter, text, length, data=None):
  1120.         # for change highlighting. just save the edit location and length here.
  1121.         # the actual highlight is applied in on_text_buffer_changed()
  1122.         self.edit_loc = iter.get_offset()
  1123.         self.edit_len = length
  1124.  
  1125.  
  1126.         # remove any find highlighting we've done
  1127.         if buff.get_tag_table().lookup("search_results"):
  1128.             buff.remove_tag_by_name('search_results', buff.get_start_iter(), buff.get_end_iter())
  1129.  
  1130.  
  1131.     #emitted AFTER text is inserted into the buffer
  1132.     #here we retrieve the location and apply the highlight tag
  1133.     def on_text_buffer_changed(self, buff,data=None):
  1134.  
  1135.         # we set edit_loc to -1 on deletions
  1136.         if self.edit_loc >=0:
  1137.             start_iter = buff.get_iter_at_offset(self.edit_loc)
  1138.             start_mark = buff.create_mark(None,start_iter)
  1139.             end_iter = buff.get_iter_at_offset(self.edit_loc + self.edit_len)
  1140.             end_mark = buff.create_mark(None,end_iter)
  1141.             self.mark_range_as_changed(buff,start_mark,end_mark)
  1142.             buff.delete_mark(start_mark)
  1143.             buff.delete_mark(end_mark)
  1144.  
  1145.     #set the edit location to -1 here so on_text_buffer_changed() doesn't
  1146.     #try to set attributes on a deleted range
  1147.     def on_text_buffer_delete_range(self,buff,start,end, data=None):
  1148.         self.edit_loc = -1
  1149.  
  1150.  
  1151.     #def on_text_buffer_mark_set(self, textbuffer, iter, textmark, data=None):
  1152.     #    if textmark.get_name() == 'insert':
  1153.     #        self.move_replace_cursor(textbuffer,iter)
  1154.  
  1155.     # We call error_message() any time we want to display an error message to
  1156.     # the user. It will both show an error dialog and log the error to the
  1157.     # terminal window.
  1158.     def error_message(self, message):
  1159.         # log to terminal window
  1160.         self.log(message)
  1161.  
  1162.         # create an error message dialog and display modally to the user
  1163.         dialog = gtk.MessageDialog(None,
  1164.                                    gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
  1165.                                    gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, message)
  1166.  
  1167.         dialog.run()
  1168.         dialog.destroy()
  1169.  
  1170.     # This function will check to see if the text buffer has been
  1171.     # modified and prompt the user to save if it has been modified.
  1172.     def check_for_save (self):
  1173.         ret = False
  1174.         buff = self.text_view.get_buffer()
  1175.  
  1176.         if buff.get_modified():
  1177.  
  1178.             # we need to prompt for save
  1179.             message = "Do you want to save the changes you have made?"
  1180.             dialog = gtk.MessageDialog(self.window,
  1181.                                        gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
  1182.                                        gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO,
  1183.                                        message)
  1184.             dialog.set_title("Save?")
  1185.  
  1186.             if dialog.run() == gtk.RESPONSE_NO: ret = False
  1187.             else: ret = True
  1188.  
  1189.             dialog.destroy()
  1190.  
  1191.         return ret
  1192.  
  1193.     # We call get_open_filename() when we want to get a filename to open from the
  1194.     # user. It will present the user with a file chooser dialog and return the
  1195.     # filename or None.
  1196.     def get_open_filename(self):
  1197.         filename = None
  1198.         chooser = gtk.FileChooserDialog("Open File...", self.window,
  1199.                                         gtk.FILE_CHOOSER_ACTION_OPEN,
  1200.                                         (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
  1201.                                          gtk.STOCK_OPEN, gtk.RESPONSE_OK))
  1202.  
  1203.         response = chooser.run()
  1204.         if response == gtk.RESPONSE_OK: filename = chooser.get_filename()
  1205.         chooser.destroy()
  1206.  
  1207.         return filename
  1208.  
  1209.     # We call get_save_filename() when we want to get a filename to save from the
  1210.     # user. It will present the user with a file chooser dialog and return the
  1211.     # filename or None.
  1212.     def get_save_filename(self):
  1213.         filename = None
  1214.         chooser = gtk.FileChooserDialog("Save File...", self.window,
  1215.                                         gtk.FILE_CHOOSER_ACTION_SAVE,
  1216.                                         (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
  1217.                                          gtk.STOCK_SAVE, gtk.RESPONSE_OK))
  1218.  
  1219.         response = chooser.run()
  1220.         if response == gtk.RESPONSE_OK: filename = chooser.get_filename()
  1221.         #if response == gtk.RESPONSE_CANCEL: print "save cancelled"
  1222.         chooser.destroy()
  1223.  
  1224.         return filename
  1225.  
  1226.  
  1227.  
  1228. ###
  1229. # do_* = controller methods called from on_* actions
  1230. ###
  1231.  
  1232.     # find
  1233.  
  1234.     def get_find_iter(self,buffer=None, backwards=False,limit_iter=None):
  1235.         find_iter = None
  1236.         selection = buffer.get_selection_bounds()
  1237.         if selection == ():
  1238.             find_iter = buffer.get_iter_at_mark(buffer.get_insert())
  1239.             if find_iter == None:
  1240.                 find_iter = buffer.get_bounds()[int(backwards)]
  1241.         else:
  1242.             find_iter = selection[int(not backwards)]
  1243.  
  1244.         return find_iter
  1245.  
  1246.  
  1247.     def do_find(self,buffer=None,iter=None,backwards=False,case_sensitive=False,whole_word=False):
  1248.  
  1249.         if self.search_string == "":
  1250.             # show the ui
  1251.             self.on_show_find_menu_item_activate(buffer)
  1252.             return
  1253.  
  1254.         find_iter = iter
  1255.  
  1256.         if find_iter == None:
  1257.             find_iter = self.get_find_iter(buffer=buffer, backwards=backwards,limit_iter=None)
  1258.  
  1259.         results = self.do_find_with_iter(find_iter, self.search_string, backwards=backwards, case_sensitive=case_sensitive,whole_word=whole_word)
  1260.  
  1261.         if results == None:
  1262.             #nothing else found. ask to wrap.
  1263.             self.log( "\'%s\' not found"%(self.search_string))
  1264.             if self.ask_for_wrap(backwards=backwards):
  1265.                 self.log("wrapping")
  1266.                 wrapped_iter = buffer.get_bounds()[int(backwards)]
  1267.                 results = self.do_find_with_iter(wrapped_iter, self.search_string, backwards=backwards, case_sensitive=case_sensitive,whole_word=whole_word)
  1268.                 if results:
  1269.                     ins, bound = results
  1270.                     buffer.select_range(ins,bound)
  1271.                     self.text_view.scroll_to_mark(mark=buffer.get_insert(),within_margin=0.33,use_align=True,xalign=0.5,yalign=0.5)
  1272.                 else:
  1273.                     # really not found. beep.
  1274.                     gtk.gdk.beep()
  1275.         else:
  1276.             #happily select and highlight
  1277.             ins, bound = results
  1278.             buffer.select_range(ins,bound)
  1279.             self.text_view.scroll_to_mark(mark=buffer.get_insert(),within_margin=0.33,use_align=True,xalign=0.5,yalign=0.5)
  1280.  
  1281.         return results
  1282.  
  1283.     def do_find_with_iter(self, iter=None, search_for=None,backwards=False,case_sensitive=False,whole_word=False):
  1284.  
  1285.         def next_match():
  1286.             results = None
  1287.             search_flags = 0
  1288.             if using_source_view:
  1289.                 if not self.search_case_sensitive:
  1290.                     search_flags = gtksourceview2.SEARCH_CASE_INSENSITIVE
  1291.                 if backwards:
  1292.                     results = gtksourceview2.iter_backward_search(iter, search_for, flags=search_flags)#, limit=limit_iter)
  1293.                 else:
  1294.                     results = gtksourceview2.iter_forward_search(iter, search_for, flags=search_flags)#, limit=limit_iter)
  1295.             else:
  1296.                 if backwards:
  1297.                     results = iter.backward_search(search_for, flags=search_flags)#, limit=limit_iter)
  1298.                 else:
  1299.                     results = iter.forward_search(search_for, flags=search_flags)#, limit=limit_iter)
  1300.             return results
  1301.  
  1302.         #test for whole word , case
  1303.         def next_whole_word():
  1304.             word_hit = None
  1305.             whole_word_hit = False
  1306.             while not whole_word_hit:
  1307.                 word_hit = next_match()
  1308.                 if word_hit:
  1309.                     if word_hit[0].starts_word() and word_hit[1].ends_word():
  1310.                         #hit = result
  1311.                         whole_word_hit = True
  1312.                         return word_hit
  1313.                     else:
  1314.                         if not backwards:
  1315.                             iter.forward_chars(len(search_for))
  1316.                         else:
  1317.                             iter.backward_chars(len(search_for))
  1318.                         #print iter.get_offset()
  1319.                         word_hit = next_match()
  1320.                 else:
  1321.                     return None
  1322.  
  1323.             return word_hit
  1324.  
  1325.         result = next_match()
  1326.  
  1327.         # test substring result for conditions
  1328.         if self.search_is_whole_word:
  1329.             hit = next_whole_word()
  1330.         else:
  1331.             hit = result
  1332.  
  1333.         return hit
  1334.  
  1335.     def ask_for_wrap(self,backwards=False):
  1336.         ret = False
  1337.  
  1338.         direction = 'beginning'
  1339.         if backwards:
  1340.             direction = 'end'
  1341.  
  1342.         message = "\'%s\' not found. Wrap and start from %s of document?"%(self.search_string,direction)
  1343.         dialog = gtk.MessageDialog(self.window,
  1344.                                    gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
  1345.                                    gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO,
  1346.                                    message)
  1347.  
  1348.         dialog.set_title("Wrap Search?")
  1349.  
  1350.         if dialog.run() == gtk.RESPONSE_NO: ret = False
  1351.         else: ret = True
  1352.  
  1353.         dialog.destroy()
  1354.  
  1355.         return ret
  1356.  
  1357.     def ask_for_replace(self):
  1358.         ret = False
  1359.  
  1360.         message = "Replace?"
  1361.         dialog = gtk.MessageDialog(self.window,
  1362.                                        gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
  1363.                                        gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO,
  1364.                                        message)
  1365.         dialog.set_title("Replace?")
  1366.  
  1367.         if dialog.run() == gtk.RESPONSE_NO: ret = False
  1368.         else: ret = True
  1369.  
  1370.         dialog.destroy()
  1371.  
  1372.         return ret
  1373.  
  1374.     def do_find_all(self,buffer=None,case_sensitive=False,whole_word=False):
  1375.         start_iter = buffer.get_start_iter()
  1376.         end_iter = buffer.get_end_iter()
  1377.  
  1378.         begin_mark = buffer.create_mark(None,start_iter)
  1379.         end_mark = buffer.create_mark(None,end_iter)
  1380.         search_results = self.find_all_in_range(buffer, self.search_string, begin_mark,end_mark)
  1381.         buffer.delete_mark(begin_mark)
  1382.         buffer.delete_mark(end_mark)
  1383.  
  1384.         if not buffer.get_tag_table().lookup("search_results"):
  1385.             preview_tag = buffer.create_tag("search_results", background_set="True",background=CONF_FIND_HIGHLIGHT)
  1386.         else:
  1387.             buffer.remove_tag_by_name('search_results', start_iter, end_iter)
  1388.  
  1389.         if search_results:
  1390.             for range in search_results:
  1391.                 if self.search_is_whole_word:
  1392.                     if range[0].starts_word() and range[1].ends_word():
  1393.                         buffer.apply_tag_by_name("search_results",range[0],range[1])
  1394.                 else:
  1395.                     buffer.apply_tag_by_name("search_results",range[0],range[1])
  1396.  
  1397.  
  1398.     def do_replace_next(self,buffer=None,iter=None,search_for='',replace_with='',limit=None):
  1399.  
  1400.         buffer.remove_tag_by_name('search_results', buffer.get_start_iter(), buffer.get_end_iter())
  1401.  
  1402.         replace_iter = iter
  1403.  
  1404.         range = self.do_find(buffer=buffer,iter=replace_iter,backwards=False,case_sensitive=self.search_case_sensitive,whole_word=self.search_is_whole_word)
  1405.  
  1406.         if range:
  1407.             if not buffer.get_tag_table().lookup("search_results"):
  1408.                 preview_tag = buffer.create_tag("search_results", background_set="True",background=CONF_FIND_HIGHLIGHT)
  1409.  
  1410.             #apply tag
  1411.             buffer.apply_tag_by_name("search_results",range[0],range[1])
  1412.  
  1413.             if not self.ask_for_replace():
  1414.                 self.log("replace declined")
  1415.                 return
  1416.  
  1417.             replace_begin = buffer.create_mark(None,range[0])
  1418.             replace_end = buffer.create_mark(None,range[1])
  1419.             replace_list = [(replace_begin,replace_end)]
  1420.  
  1421.  
  1422.             replaced_range = self.replace_text(buffer,replace_with,replace_list)
  1423.  
  1424.             self.text_view.scroll_to_mark(replace_end,0)
  1425.             buffer.delete_mark(replace_begin)
  1426.             buffer.delete_mark(replace_end)
  1427.  
  1428.  
  1429.     def do_replace_all(self,buffer,search_for,replace_with):
  1430.         #search_results = self.search_for_text(buffer,search_for,buffer.get_start_iter(),buffer.get_end_iter())
  1431.         replace_begin = buffer.create_mark(None,buffer.get_start_iter())
  1432.         replace_end = buffer.create_mark(None,buffer.get_end_iter())
  1433.         search_results = self.find_all_in_range(buffer,search_for,replace_begin,replace_end)
  1434.  
  1435.         result_marks = []
  1436.         for iter_pair in search_results:
  1437.             this_mark_pair = []
  1438.             for iter in iter_pair:
  1439.                 this_mark = buffer.create_mark(None,iter)
  1440.                 this_mark_pair.append(this_mark)
  1441.             self.edit_loc = iter_pair[0]#wft
  1442.  
  1443.             result_marks.append(this_mark_pair)
  1444.  
  1445.         self.replace_text(buffer,replace_with,result_marks)
  1446.  
  1447.         for that_mark_pair in result_marks:
  1448.             for that_mark in that_mark_pair:
  1449.                 buffer.delete_mark(that_mark)
  1450.  
  1451.         buffer.delete_mark(replace_begin)
  1452.         buffer.delete_mark(replace_end)
  1453.  
  1454.  
  1455.     def find_all_in_range(self, buff, search_string, start_mark, end_mark):
  1456.         start_iter = buff.get_iter_at_mark(start_mark)
  1457.         end_iter = buff.get_iter_at_mark(end_mark)
  1458.         search_results = []
  1459.  
  1460.         next_result = self.do_find_with_iter(iter=start_iter,search_for=self.search_string,backwards=False,case_sensitive=self.search_case_sensitive,whole_word=self.search_is_whole_word)
  1461.         while next_result:
  1462.             #self.search_for_text(buff,search_string,start_iter,end_iter)
  1463.             search_results.append(next_result)
  1464.             next_result = self.do_find_with_iter(iter=next_result[1],search_for=self.search_string,backwards=False,case_sensitive=self.search_case_sensitive,whole_word=self.search_is_whole_word)
  1465.  
  1466.         return search_results
  1467.  
  1468.     def guess_encoding(self,data):
  1469.         """
  1470.        Given a byte string, attempt to decode it.
  1471.        Tries the standard 'UTF8' and 'latin-1' encodings,
  1472.        Plus several gathered from locale information.
  1473.  
  1474.        The calling program *must* first call
  1475.            locale.setlocale(locale.LC_ALL, '')
  1476.  
  1477.        If successful it returns
  1478.            (decoded_unicode, successful_encoding)
  1479.        If unsuccessful it raises a ``UnicodeError``
  1480.        """
  1481.         import locale
  1482.  
  1483.         successful_encoding = None
  1484.         # we make 'utf-8' the first encoding
  1485.         encodings = ['utf-8']
  1486.         #
  1487.         # next we add anything we can learn from the locale
  1488.         try:
  1489.             encodings.append(locale.nl_langinfo(locale.CODESET))
  1490.         except AttributeError:
  1491.             pass
  1492.         try:
  1493.             encodings.append(locale.getlocale()[1])
  1494.         except (AttributeError, IndexError):
  1495.             pass
  1496.         try:
  1497.             encodings.append(locale.getdefaultlocale()[1])
  1498.         except (AttributeError, IndexError):
  1499.             pass
  1500.         #
  1501.         # we try 'latin-1' last
  1502.         encodings.append('latin-1')
  1503.         for enc in encodings:
  1504.             # some of the locale calls
  1505.             # may have returned None
  1506.             if not enc:
  1507.                 continue
  1508.             try:
  1509.                 decoded = unicode(data, enc)
  1510.                 successful_encoding = enc
  1511.  
  1512.             except (UnicodeError, LookupError):
  1513.                 pass
  1514.             else:
  1515.                 break
  1516.         if not successful_encoding:
  1517.              raise UnicodeError(
  1518.             'Unable to decode input data.  Tried the following encodings: %s.'
  1519.             % ', '.join([repr(enc) for enc in encodings if enc]))
  1520.         else:
  1521.              return (decoded, successful_encoding)
  1522.  
  1523.  
  1524.     #thanks to http://www.pyzine.com/Issue008/Section_Articles/article_Encodings.html
  1525.     def decode_text(self,the_text=None):
  1526.         # adapted from io.py
  1527.         # in the docutils extension module
  1528.         # see http://docutils.sourceforge.net
  1529.         import codecs
  1530.         import locale
  1531.         import sys
  1532.  
  1533.         # uses the guess_encoding function from above
  1534.  
  1535.         bomdict = {
  1536.                          codecs.BOM_UTF8 : 'UTF8',
  1537.                  codecs.BOM_UTF16_BE : 'UTF-16BE',
  1538.                  codecs.BOM_UTF16_LE : 'UTF-16LE' }
  1539.  
  1540.         # check if there is Unicode signature
  1541.         for bom, encoding in bomdict.items():
  1542.             if the_text.startswith(bom):
  1543.                 the_text = the_text[len(bom):]
  1544.                 break
  1545.             else:
  1546.                bom  = None
  1547.                encoding = None
  1548.  
  1549.         if encoding is None:    # there was no BOM
  1550.             try:
  1551.                 unicode_text, encoding = self.guess_encoding(the_text)
  1552.             except UnicodeError:
  1553.                 print "Sorry - we can't work out the encoding."
  1554.                 raise
  1555.         else:
  1556.             # we found a BOM so we know the encoding
  1557.             unicode_text = the_text.decode(encoding)
  1558.         # now you have your Unicode text.. and can do with it what you will
  1559.  
  1560.         # now we want to re-encode it to a byte string
  1561.         # so that we can write it back out
  1562.         # we will reuse the original encoding, and preserve any BOM
  1563.         if bom is not None:
  1564.             if encoding.startswith('UTF-16'):
  1565.             # we will use the right 'endian-ness' for this machine
  1566.                 encoding = 'UTF-16'
  1567.                 bom = codecs.BOM_UTF16
  1568.         byte_string = unicode_text.encode(encoding)
  1569.         if bom is not None:
  1570.             byte_string = bom + byte_string
  1571.         # now we have the text encoded as a byte string, ready to be saved to a file
  1572.  
  1573.         return byte_string
  1574.  
  1575.  
  1576.     # We call load_file() when we have a filename and want to load it into the
  1577.     # buffer for the GtkTextView. The previous contents are overwritten.
  1578.     def load_file(self, filename):
  1579.         # add Loading message to status bar and ensure GUI is current
  1580.         self.statusbar.push(self.statusbar_cid, "Loading %s" % filename)
  1581.         while gtk.events_pending():
  1582.             gtk.main_iteration()
  1583.  
  1584.         buff = self.text_view.get_buffer()
  1585.         if using_source_view:
  1586.             try:
  1587.                 buff.begin_not_undoable_action()
  1588.             except AttributeError:
  1589.                 pass
  1590.  
  1591.         try:
  1592.             # get the file contents
  1593.             fin = open(filename, "r")
  1594.             text_data = fin.read()
  1595.             fin.close()
  1596.  
  1597.             # disable the text view while loading the buffer with the text
  1598.             self.text_view.set_sensitive(False)
  1599.  
  1600.  
  1601.             #unicode?
  1602.             #buff.set_text(text)
  1603.             the_text,the_encoding = self.guess_encoding(text_data)
  1604.             buff.set_text(the_text)
  1605.             self.text_encoding = the_encoding
  1606.             print "encoding: %s"%self.text_encoding
  1607.  
  1608.             # reenable text view and set everything up for the user
  1609.             buff.set_modified(False)
  1610.             self.text_view.set_sensitive(True)
  1611.  
  1612.             # now we can set the window's filename since loading was a success
  1613.             self.filename = filename
  1614.  
  1615.         except:
  1616.             # error loading file, show message to user
  1617.             self.error_message ("Could not open file: %s\n%s" % (filename,sys.exc_info()[0]))
  1618.             raise
  1619.  
  1620.         # syntax highlighting
  1621.         if using_source_view:
  1622.             if CONF_HIGHLIGHT_SYNTAX:
  1623.                 buffer = self.text_view.get_buffer()
  1624.                 f = gio.File(filename)
  1625.                 path = f.get_path()
  1626.  
  1627.                 info = f.query_info("*")
  1628.  
  1629.                 mime_type = info.get_content_type()
  1630.                 language = None
  1631.  
  1632.                 if mime_type:
  1633.                     language = self.get_language_for_mime_type(mime_type)
  1634.  
  1635.                     if language:
  1636.                         self.language = language.get_name()
  1637.                     if not language:
  1638.                         #self.error_message('No language found for mime type "%s"' % mime_type)
  1639.                         self.language = 'None'
  1640.                 else:
  1641.                     self.error_message('Couldn\'t get mime type for file "%s"' % filename)
  1642.  
  1643.                 try:
  1644.                     buffer.set_language(language)
  1645.  
  1646.                     buffer.set_highlight_syntax(CONF_HIGHLIGHT_SYNTAX)
  1647.                 except AttributeError:
  1648.                     pass
  1649.  
  1650.         # move insertion point and scroll to top
  1651.         buff.place_cursor(buff.get_start_iter())
  1652.  
  1653.         if using_source_view:
  1654.             try:
  1655.                 self.text_view.get_buffer().end_not_undoable_action()
  1656.             except AttributeError:
  1657.                 pass
  1658.  
  1659.         # clear loading status and restore default
  1660.         self.statusbar.pop(self.statusbar_cid)
  1661.         self.reset_default_status()
  1662.  
  1663.     def write_file(self, filename):
  1664.         # add Saving message to status bar and ensure GUI is current
  1665.         if filename:
  1666.             self.statusbar.push(self.statusbar_cid, "Saving %s" % filename)
  1667.         else:
  1668.             self.statusbar.push(self.statusbar_cid, "Saving %s" % self.filename)
  1669.  
  1670.         while gtk.events_pending(): gtk.main_iteration()
  1671.  
  1672.         try:
  1673.             # disable text view while getting contents of buffer
  1674.             buff = self.text_view.get_buffer()
  1675.             self.text_view.set_sensitive(False)
  1676.             text = buff.get_text(buff.get_start_iter(), buff.get_end_iter())
  1677.  
  1678.         if self.text_encoding == None:
  1679.         self.text_encoding = "utf-8"
  1680.             text_data = text.encode(self.text_encoding)
  1681.  
  1682.             self.text_view.set_sensitive(True)
  1683.             buff.set_modified(False)
  1684.  
  1685.             # set the contents of the file to the text from the buffer
  1686.             if filename: fout = open(filename, "w")
  1687.             else: fout = open(self.filename, "w")
  1688.             fout.write(text_data)
  1689.             fout.close()
  1690.  
  1691.             if filename: self.filename = filename
  1692.         except:
  1693.             # error writing file, show message to user
  1694.             self.error_message ("Could not save file: %s" % filename)
  1695.  
  1696.         # clear saving status and restore default
  1697.         self.statusbar.pop(self.statusbar_cid)
  1698.         self.reset_default_status()
  1699.  
  1700.     ######################################################################
  1701.     ##### Note this function is silly and wrong, because it ignores mime
  1702.     ##### parent types and subtypes.
  1703.     # i don't care i'm using it anyway
  1704.     def get_language_for_mime_type(self,mime):
  1705.         lang_manager = gtksourceview2.language_manager_get_default()
  1706.         lang_ids = lang_manager.get_language_ids()
  1707.         for i in lang_ids:
  1708.             lang = lang_manager.get_language(i)
  1709.             for m in lang.get_mime_types():
  1710.                 if m == mime:
  1711.                     return lang
  1712.         return None
  1713.  
  1714.     def mark_window_status(self,window,changed):
  1715.         if changed:
  1716.             if not window.get_title()[0] == "*":
  1717.                 window.set_title("*" + window.get_title())
  1718.  
  1719.     class StatusBarManager:
  1720.         def __init__(self):
  1721.             self.filename = "(UNTITLED)"
  1722.             self.language = "(NONE)"
  1723.             self.encoding = "utf-8" #get default encoding
  1724.             self.status_line = {}
  1725.             self.statusbar = None
  1726.  
  1727.         def StatusBarManager(self, statusbar=None, language=None,filename=None,encoding=None):
  1728.             self.set_language(language)
  1729.             self.set_filename(filename)
  1730.             self.set_encoding(encoding)
  1731.             self.set_statusbar(statusbar)
  1732.  
  1733.         def set_language(self,language=None):
  1734.             self.language = language
  1735.             self.status_line['Language'] = self.language
  1736.             self.update_status()
  1737.  
  1738.  
  1739.         def set_encoding(self,encoding=None):
  1740.             self.encoding = encoding
  1741.             self.status_line['Encoding'] = self.encoding
  1742.             self.update_status()
  1743.  
  1744.         def set_filename(self,filename=None):
  1745.             self.filename = filename
  1746.             self.status_line['File'] = self.filename
  1747.             self.update_status()
  1748.  
  1749.  
  1750.         def set_statusbar(self,statusbar=None):
  1751.             self.statusbar = statusbar
  1752.  
  1753.  
  1754.         def update_status(self):
  1755.             cid = self.statusbar.get_context_id("Edile GTK+ Text Editor")
  1756.             self.statusbar.push(cid,self.get_status())
  1757.  
  1758.  
  1759.         def reset_status(self):
  1760.             self.update_status()
  1761.  
  1762.         def set_status(self,string):
  1763.             cid = self.statusbar.get_context_id("Edile GTK+ Text Editor")
  1764.             self.statusbar.push(cid,string)
  1765.  
  1766.         def get_status(self):
  1767.             status_string = "File: %s | Language: %s | Encoding: %s"%(self.filename,self.language,self.encoding)
  1768.  
  1769.             return status_string
  1770.  
  1771.     class PluginInterface:
  1772.  
  1773.         def set_parent(self,parent=None):
  1774.             self.parent = parent
  1775.  
  1776.         def replace_selection(self,new_text=None):
  1777.             #create marks
  1778.             range = self.get_selected_range()
  1779.             buff = self.get_buffer()
  1780.             start = buff.create_mark(None,range[0])
  1781.             end = buff.create_mark(None,range[1])
  1782.             repl = self.parent.replace_text(buff,new_text,[(start,end)])
  1783.             buff.select_range(buff.get_iter_at_mark(start),buff.get_iter_at_mark(end))
  1784.             buff.delete_mark(start)
  1785.             buff.delete_mark(end)
  1786.  
  1787.         def insert(self,text=None):
  1788.             if text:
  1789.                 self.parent.text_view.get_buffer().insert_at_cursor(text)
  1790.  
  1791.         def select(self,start,end):
  1792.             self.get_buffer().select_range(end,start)
  1793.  
  1794.         def get_selection(self):
  1795.             range = self.parent.text_view.get_buffer().get_selection_bounds()
  1796.             return self.parent.text_view.get_buffer().get_text(range[0],range[1])
  1797.  
  1798.         def get_selected_range(self):
  1799.             return self.parent.text_view.get_buffer().get_selection_bounds()
  1800.  
  1801.         def open_file(self,path=None):
  1802.             self.parent.spawn(path)
  1803.             return
  1804.  
  1805.         def get_text(self):
  1806.             buf = self.parent.text_view.get_buffer()
  1807.             return buf.get_text(buf.get_start_iter(),buf.get_end_iter())
  1808.  
  1809.         def message(self,string=None):
  1810.             self.parent.error_message(string)
  1811.  
  1812.         def get_language(self):
  1813.             return self.parent.language
  1814.  
  1815.         def get_buffer(self):
  1816.             return self.parent.text_view.get_buffer()
  1817.  
  1818.         def get_filename(self):
  1819.             return self.parent.filename
  1820.  
  1821.  
  1822.     def on_drag_motion(self,wid, context, x, y, time):
  1823.         context.drag_status(gtk.gdk.ACTION_COPY, time)
  1824.         #path = context.drag_get_selection()
  1825.         path = ""
  1826.         self.statusbar_manager.set_status('Open: %s'%(path))
  1827.         return True
  1828.  
  1829.    # def on_drag_drop(self,wid, context, x, y, time):
  1830.    #     self.text_view.get_buffer().set_text('\n'.join([str(t) for t in context.targets]))
  1831.    #     #load file
  1832.    #     wid.drag_get_data()
  1833.    #     context.finish(True, False, time)
  1834.    #     return True
  1835.     def on_drag_end(self,widget, drag_context, data):
  1836.         self.statusbar_manager.reset_status()
  1837.  
  1838.     def on_drag_data_received(self,widget, drag_context, x, y, selection, target_type, time, data):
  1839.         if target_type == 80:
  1840.             uri = selection.data.strip('\r\n\x00')
  1841.             uri_splitted = uri.split() # we may have more than one file dropped
  1842.             #for uri in uri_splitted:
  1843.             #print uri_splitted
  1844.             uri = uri_splitted[0]
  1845.             path = self.get_file_path_from_dnd_dropped_uri(uri)
  1846.             #path = urlparse.urlparse(uri).path
  1847.             #print path
  1848.             if os.path.isfile(path):
  1849.                 if self.check_for_save():
  1850.                     self.on_save_menu_item_activate(None, None)
  1851.                     # if user cancelled save
  1852.                     if self.filename == None: return
  1853.                 self.load_file(path)
  1854.  
  1855.                 drag_context.finish(success=True, del_=False, time=time)
  1856.                 #drag_context.drop_finish(True,time)
  1857.             else:
  1858.                 #drag_context.drop_finish(False,time)
  1859.                 drag_context.finish(success=False, del_=False, time=time)
  1860.  
  1861.  
  1862.     def get_file_path_from_dnd_dropped_uri(self,uri):
  1863.         # get the path to file
  1864.         path = ""
  1865.         if uri.startswith('file:\\\\\\'): # windows
  1866.             path = uri[8:] # 8 is len('file:///')
  1867.         elif uri.startswith('file://'): # nautilus, rox
  1868.             path = uri[7:] # 7 is len('file://')
  1869.         elif uri.startswith('file:'): # xffm
  1870.             path = uri[5:] # 5 is len('file:')
  1871.  
  1872.         path = urllib.url2pathname(path) # escape special chars
  1873.         path = path.strip('\r\n\x00') # remove \r\n and NULL
  1874.  
  1875.         return path
  1876.  
  1877.     def running_as_root(self):
  1878.         return (os.name == 'posix') and (os.geteuid() == 0)
  1879.  
  1880.     def reset_default_status(self):
  1881.         if self.filename:
  1882.             status = "File: %s" % self.filename #os.path.basename(self.filename)
  1883.             self.window.set_title("%s | Edile Text Editor" % os.path.basename(self.filename))
  1884.         else:
  1885.             status = "File: (UNTITLED)"
  1886.             self.window.set_title("Untitled | Edile Text Editor")
  1887.  
  1888.         #check for root
  1889.         #if platform.system() is not "Windows":
  1890.         if self.running_as_root():
  1891.             old_title = self.window.get_title()
  1892.             new_title = old_title + " | RUNNING AS ROOT"
  1893.             self.window.set_title(new_title)
  1894.  
  1895.         self.statusbar.pop(self.statusbar_cid)
  1896.         self.statusbar.push(self.statusbar_cid, status)
  1897.  
  1898.         self.statusbar_manager.set_filename(self.filename)
  1899.         self.statusbar_manager.set_language(self.language)
  1900.         self.statusbar_manager.set_encoding(self.text_encoding)
  1901.  
  1902.         buff = self.text_view.get_buffer()
  1903.         buff.remove_tag_by_name("change_highlight",buff.get_start_iter(),buff.get_end_iter())
  1904.  
  1905.         #self.move_replace_cursor(buff,buff.get_start_iter())
  1906.  
  1907.         self.text_view.grab_focus()
  1908.  
  1909.     def search_for_text(self, txtbuf, text, begin, end):
  1910.         """
  1911.        Search for text within a specified text buffer.
  1912.  
  1913.        This function searches for the text within the boundaries specified by begin
  1914.        and end in a specified text buffer. If matches are found the function
  1915.        returns the position of the found matches represented by pairs of
  1916.        gtk.TextMarks. Otherwise, the functions returns an empty List.
  1917.  
  1918.        @param txtbuf: Reference to the text buffer to search.
  1919.        @type editor: A gtk.TextBuffer object.
  1920.  
  1921.        @param text: The string to search for in the text editor's buffer.
  1922.        @type text: A String object.
  1923.  
  1924.        @param begin: The position in the buffer to begin searching for text.
  1925.        @type begin: A gtk.TextIter object.
  1926.  
  1927.        @param end: The position in the buffer to stop searching for text.
  1928.        @type end: A gtk.TextIter object.
  1929.  
  1930.        @return: The position of found matches in the buffer.
  1931.        @rtype: A List object containing pairs of gtk.TextIter or None.
  1932.        """
  1933.         found_matches = []
  1934.         from gtk import TEXT_SEARCH_VISIBLE_ONLY
  1935.         while True:
  1936.             result = begin.forward_search(text, TEXT_SEARCH_VISIBLE_ONLY, end)
  1937.             if result:
  1938.                 found_matches.append((result[0], result[1]))
  1939.                 begin = result[1]
  1940.             else:
  1941.                 break
  1942.         return found_matches
  1943.  
  1944.     def mark_range_as_changed(self,txtbuf,start_mark,end_mark):
  1945.  
  1946.         if self.highlight_changes:
  1947.             begin = txtbuf.get_iter_at_mark(start_mark)
  1948.             end = txtbuf.get_iter_at_mark(end_mark)
  1949.             txtbuf.apply_tag_by_name("change_highlight",begin,end)
  1950.  
  1951.     def replace_text(self, txtbuf, text, positions):
  1952.         """
  1953.        Replace text at specified positions in a text buffer with one specified as
  1954.        a parameter.
  1955.  
  1956.        @param txtbuf: Reference to a text buffer where replacement should occur.
  1957.        @type txtbuf: A gtk.TextBuffer object.
  1958.  
  1959.        @param text: Text to insert into the text buffer.
  1960.        @type text: A String object.
  1961.  
  1962.        @param positions: Positions in the text buffer to replace text.
  1963.        @type positions: A List object containing pairs of gtk.TextMarks.
  1964.        """
  1965.  
  1966.         replaced_ranges = []
  1967.         for marks in positions:
  1968.             begin = txtbuf.get_iter_at_mark(marks[0])
  1969.             end = txtbuf.get_iter_at_mark(marks[1])
  1970.             txtbuf.delete(begin, end)
  1971.             begin = txtbuf.get_iter_at_mark(marks[0])
  1972.             txtbuf.insert(begin, text)
  1973.             replaced_ranges.append((marks[0],marks[1]))
  1974.  
  1975.         return replaced_ranges
  1976.  
  1977.     #spawn a new edile instance
  1978.     def spawn(self, file=None):
  1979.         exe = __file__
  1980.         exepath = os.path.realpath(exe)
  1981.         if file:
  1982.             path = os.path.realpath( file )
  1983.         else:
  1984.             path = ""
  1985.  
  1986.         #doesnt use subprocess
  1987.         #os.system("%s \"%s\"&"% (exepath,path))
  1988.         child_pid = subprocess.Popen([exepath, path]).pid
  1989.  
  1990.         self.log("new %s instance pid %d"%(os.path.basename(exepath),child_pid))
  1991.  
  1992.     def plugin_load_from_url(self,url):
  1993.         plugin_string = urllib.urlopen(url).read()
  1994.  
  1995.         #plugin_file = tempfile.NamedTemporaryFile()
  1996.         #plugin_file.write(plugin_string)
  1997.         #print plugin_file.name
  1998.  
  1999.         return plugin_string
  2000.  
  2001.     def plugin_getfunctions(self,module):
  2002.         l = []
  2003.         for key, value in module.__dict__.items():
  2004.             if type(value) is types.FunctionType:
  2005.                 l.append(value)
  2006.         return l
  2007.  
  2008.     def plugin_get_plugins(self):
  2009.             plugin_tree = {}
  2010.  
  2011.             if CONF_PLUGIN_LOCATION == "": return
  2012.  
  2013.             plugin_string = self.plugin_load_from_url(CONF_PLUGIN_LOCATION)
  2014.  
  2015.             if plugin_string:
  2016.                 plugin_hash = hashlib.sha256(plugin_string).hexdigest()
  2017.  
  2018.                 if (plugin_hash == CONF_PLUGIN_SHA256) or (CONF_PLUGIN_SHA256 == ''):
  2019.                     plugins = imp.new_module("plugins")
  2020.                     exec(plugin_string, plugins.__dict__)
  2021.                     #print plugins.__dict__['Tools'].shortcuts
  2022.                 else:
  2023.                     self.error_message("plugin authentication failed")
  2024.                     quit()
  2025.  
  2026.  
  2027.             #pl = imp.load_source("plugins",plugin_file) #path only
  2028.  
  2029.             for thing in plugins.__dict__:
  2030.                 if thing[:2] != "__":
  2031.                 #if type(thing) is types.MethodType:
  2032.                     pl_key = (thing,plugins.__dict__[thing])
  2033.                     plugin_tree[pl_key] = self.plugin_getfunctions(plugins.__dict__[thing])
  2034.  
  2035.             #print plugin_tree
  2036.             return plugin_tree
  2037.  
  2038.  
  2039.     def plugin_create_menus(self,plugins=None):
  2040.  
  2041.         menus = []
  2042.         for each in plugins.keys():
  2043.             the_plugin = plugins[each]
  2044.             the_menubar_item = gtk.MenuItem(each[0],False)
  2045.             the_menu = gtk.Menu()
  2046.  
  2047.             #the_menu.set_title(each)
  2048.  
  2049.             #kbd shortcutss
  2050.  
  2051.             for each_function in the_plugin:
  2052.                 item_title = string.capwords(each_function.__name__.replace('_',' '))
  2053.                 #create menu item
  2054.                 menu_item = gtk.MenuItem(item_title,False)
  2055.                 #connect() to function
  2056.                 menu_item.connect('activate',each_function,self.plugin_interface)
  2057.  
  2058.                 agr = gtk.AccelGroup()
  2059.                 self.window.add_accel_group(agr)
  2060.  
  2061.  
  2062.                 # i totally forgot how this works, but it does.
  2063.                 # doesn't look too complicated.
  2064.                 if hasattr(each[1],"shortcuts"):
  2065.  
  2066.                     if each[1].shortcuts.has_key(each_function):
  2067.                         shortcut = each[1].shortcuts[each_function]
  2068.                         key, mod = gtk.accelerator_parse(shortcut)
  2069.  
  2070.                         if key:
  2071.                             menu_item.add_accelerator("activate", agr, key, mod, gtk.ACCEL_VISIBLE)
  2072.  
  2073.                 #add to the menu
  2074.                 the_menu.append(menu_item)
  2075.  
  2076.             the_menubar_item.set_submenu(the_menu)
  2077.  
  2078.             menus.append(the_menubar_item)
  2079.  
  2080.         return menus
  2081.  
  2082.     def plugin_add_menus(self,menubar=None,plugin_menus=None):
  2083.         #insert plugin menus into the menu bar before the Help menu
  2084.         [menubar.insert(every_menu,4) for every_menu in plugin_menus]
  2085.  
  2086.     # output in a friendly fashion
  2087.     def log(self,string):
  2088.         instance_name = self.window.get_title()
  2089.         pid = '[%d]'%(os.getpid())
  2090.  
  2091.         print "%s %s %s"%(instance_name,pid,string)
  2092.  
  2093.     def load_plugins(self):
  2094.         should_load = CONF_LOAD_PLUGINS and CONF_PLUGIN_LOCATION != ""
  2095.  
  2096.         if should_load:
  2097.             if CONF_LOAD_PLUGINS_AS_ROOT == False:
  2098.                 should_load = not self.running_as_root()
  2099.  
  2100.         if should_load:
  2101.             pluginlist = self.plugin_get_plugins()
  2102.             plugin_menus = self.plugin_create_menus(pluginlist)
  2103.  
  2104.             self.plugin_add_menus(self.menubar,plugin_menus)
  2105.             self.window.show_all()
  2106.  
  2107.     # setter methods for options
  2108.     def set_auto_indent(self, indent=CONF_AUTO_INDENT):
  2109.         self.text_view.set_auto_indent(CONF_AUTO_INDENT)
  2110.  
  2111.     def set_highlight_changes(self, highlight=CONF_HIGHLIGHT_CHANGES_SINCE_SAVE):
  2112.         self.highlight_changes = highlight
  2113.  
  2114.     def set_highlight_current_line(self, highlight=CONF_HIGHLIGHT_CURRENT_LINE):
  2115.         self.text_view.set_highlight_current_line(highlight)
  2116.  
  2117.     def set_show_line_numbers(self, number=CONF_SHOW_LINE_NUMBERS):
  2118.         self.text_view.set_show_line_numbers(number)
  2119.  
  2120.     def set_show_right_margin(self, margin=CONF_SHOW_RIGHT_MARGIN):
  2121.         self.text_view.set_show_right_margin(margin)
  2122.  
  2123.     def set_insert_spaces_instead_of_tabs(self, insert=CONF_SPACES_INSTEAD_OF_TABS):
  2124.         self.text_view.set_insert_spaces_instead_of_tabs(insert)
  2125.  
  2126.     def set_tab_width(self, width=CONF_TAB_WIDTH):
  2127.         self.text_view.set_tab_width(width)
  2128.  
  2129.     def set_indent_width(self, width=CONF_INDENT_WIDTH):
  2130.         self.text_view.set_indent_width(width)
  2131.  
  2132.     def set_smart_home_end(self, type=CONF_SMART_HOME_END_TYPE_MAP[CONF_SMART_HOME_END_TYPE[0]]):
  2133.         self.text_view.set_smart_home_end(type)
  2134.  
  2135.     def set_indent_on_tab(self, indent=CONF_INDENT_ON_TAB):
  2136.         self.text_view.set_indent_on_tab(indent)
  2137.  
  2138.     def set_right_margin_position(self, pos=CONF_RIGHT_MARGIN_POSITION):
  2139.         self.text_view.set_right_margin_position(pos)
  2140.  
  2141.     def set_highlight_syntax(self, highlight=CONF_HIGHLIGHT_SYNTAX):
  2142.         self.text_view.get_buffer().set_highlight_syntax(highlight)
  2143.  
  2144.     def set_highlight_matching_brackets(self, highlight=CONF_HIGHLIGHT_MATCHING_BRACKETS):
  2145.         self.text_view.get_buffer().set_highlight_matching_brackets(highlight)
  2146.  
  2147.     def set_max_undo_levels(self, levels=CONF_MAX_UNDO_LEVELS):
  2148.         self.text_view.get_buffer().set_max_undo_levels(levels)
  2149.  
  2150.     def set_wrap_mode(self, mode=CONF_WRAP_MAP['None']):
  2151.         mode = CONF_WRAP_MAP[self.wrapping]
  2152.         self.text_view.set_wrap_mode(mode)
  2153.  
  2154.     def set_wrapping(self, wrap=CONF_WRAP[0]):
  2155.         self.wrapping = wrap
  2156.  
  2157.     def set_font(self, font=CONF_FONT):
  2158.         self.text_view.modify_font(pango.FontDescription(font))
  2159.  
  2160.     def set_overwrite(self, overwrite=CONF_OVERWRITE):
  2161.         self.text_view.set_overwrite(overwrite)
  2162.  
  2163.     def set_style_scheme(self, scheme=CONF_STYLE_SCHEME[0]):
  2164.             mgr = gtksourceview2.style_scheme_manager_get_default()
  2165.             style_scheme = mgr.get_scheme(scheme)
  2166.             if style_scheme:
  2167.                 self.text_view.get_buffer().set_style_scheme(style_scheme)
  2168.  
  2169.     # We use the initialization of the Edile class to establish
  2170.     # references to the widgets we'll need to work with in the callbacks for
  2171.     # various signals. This is done using the XML in the U_I string
  2172.     def __init__(self):
  2173.         # Default values
  2174.         self.filename = None
  2175.         self.language = None
  2176.         self.text_encoding = None
  2177.         self.about_dialog = None
  2178.         self.search_string = ""
  2179.         self.replacement_string = ""
  2180.         self.font_dialog = None
  2181.         self.edit_loc = 0
  2182.         self.edit_len = 0
  2183.         self.search_did_wrap = False
  2184.  
  2185.         self.plugin_interface = Edile.PluginInterface()
  2186.         self.plugin_interface.set_parent(self)
  2187.  
  2188.         # search options
  2189.         self.search_case_sensitive = False
  2190.         self.search_is_whole_word = False
  2191.  
  2192.         import locale
  2193.         locale.setlocale(locale.LC_ALL, '')
  2194.  
  2195.         self.set_highlight_changes(CONF_HIGHLIGHT_CHANGES_SINCE_SAVE)
  2196.  
  2197.         # use GtkBuilder to build our interface from the XML file
  2198.         try:
  2199.             builder = gtk.Builder()
  2200.             #need to specify len() to work around pygtk <2.13 bug.
  2201.             builder.add_from_string(U_I,len(U_I))
  2202.             builder.add_from_string(SEARCH_UI,len(SEARCH_UI))
  2203.         except:
  2204.             self.error_message("Failed to load UI")
  2205.             sys.exit(1)
  2206.  
  2207.         # get the widgets which will be referenced in callbacks
  2208.         self.window = builder.get_object("window")
  2209.         self.statusbar = builder.get_object("statusbar")
  2210.         self.text_view = builder.get_object("text_view")
  2211.         self.scroll_view = builder.get_object("scrolledwindow")
  2212.         self.search_window = builder.get_object('search_window')
  2213.         self.search_field = builder.get_object("search_find_field")
  2214.         self.replace_field = builder.get_object("search_replace_field")
  2215.         self.menubar = builder.get_object("menubar1")
  2216.  
  2217.  
  2218.         ###
  2219.         # command line options
  2220.         ###
  2221.         parser = OptionParser()
  2222.         parser.add_option("-p", "--plain-text", action="store_false", dest="using_source_view", default=True, help="don't use GTKSourceView if available")
  2223.         parser.add_option("-q", "--quiet", action="store_false", dest="verbose", default=True, help="don't print status messages to stdout")
  2224.  
  2225.         (options, args) = parser.parse_args()
  2226.         using_source_view = options.using_source_view
  2227.         #if parser.has_option("plain-text"):
  2228.  
  2229.         # to switch off option parser
  2230.         #args = sys.argv
  2231.  
  2232.  
  2233.  
  2234.  
  2235.         #gtksourceview is installed and we should use it, set up dev stuff
  2236.         if (using_source_view):
  2237.         #if 0:
  2238.             self.scroll_view.remove(self.text_view)
  2239.             self.text_view = gtksourceview2.View()
  2240.             self.set_auto_indent(CONF_AUTO_INDENT)
  2241.             self.set_highlight_current_line(CONF_HIGHLIGHT_CURRENT_LINE)
  2242.             self.set_show_line_numbers(CONF_SHOW_LINE_NUMBERS)
  2243.             self.set_show_right_margin(CONF_SHOW_RIGHT_MARGIN)
  2244.             self.set_insert_spaces_instead_of_tabs(CONF_SPACES_INSTEAD_OF_TABS)
  2245.             self.set_tab_width(CONF_TAB_WIDTH)
  2246.             self.set_indent_width(CONF_INDENT_WIDTH)
  2247.             self.set_right_margin_position(CONF_RIGHT_MARGIN_POSITION)
  2248.             self.set_smart_home_end(CONF_SMART_HOME_END_TYPE_MAP[CONF_SMART_HOME_END_TYPE[0]])
  2249.             self.set_indent_on_tab(CONF_INDENT_ON_TAB)
  2250.  
  2251.             # make a buffer for the view
  2252.             self.text_view.set_buffer(gtksourceview2.Buffer())
  2253.  
  2254.             # configure the source view buffer
  2255.             self.set_highlight_syntax(CONF_HIGHLIGHT_SYNTAX)
  2256.             self.set_highlight_matching_brackets(CONF_HIGHLIGHT_MATCHING_BRACKETS)
  2257.             self.set_max_undo_levels(CONF_MAX_UNDO_LEVELS)
  2258.             self.text_view.show()
  2259.             self.text_view.set_events(gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK)
  2260.             self.text_view.set_left_margin(2)
  2261.             self.text_view.set_right_margin(2)
  2262.             self.scroll_view.add(self.text_view)
  2263.  
  2264.             self.set_style_scheme()
  2265.  
  2266.         # non-gtksrcview-exclusive options
  2267.         # set the text view font
  2268.         self.set_font(CONF_FONT)
  2269.  
  2270.         self.set_overwrite(CONF_OVERWRITE)
  2271.  
  2272.         # set the text view wrapping
  2273.         self.set_wrapping(CONF_WRAP[0])
  2274.  
  2275.         if not self.wrapping: self.wrapping = 'None'
  2276.  
  2277.         self.set_wrap_mode(CONF_WRAP_MAP[self.wrapping])
  2278.  
  2279.         wrap_none_menu_item = builder.get_object("wrap_none_menu_item")
  2280.         wrap_char_menu_item = builder.get_object("wrap_char_menu_item")
  2281.         wrap_word_menu_item = builder.get_object("wrap_word_menu_item")
  2282.  
  2283.         if self.wrapping == 'None' : wrap_none_menu_item.set_active(True)
  2284.         if self.wrapping == 'Character' : wrap_char_menu_item.set_active(True)
  2285.         if self.wrapping == 'Word' : wrap_word_menu_item.set_active(True)
  2286.  
  2287.         self.statusbar_manager = Edile.StatusBarManager()
  2288.         self.statusbar_manager.set_statusbar(self.statusbar)
  2289.  
  2290.         buff = self.text_view.get_buffer()
  2291.         self.change_highlight = buff.create_tag("change_highlight", background_set="True",background=CONF_CHANGE_HIGHLIGHT)
  2292.         buff.connect("modified-changed", self.on_text_buffer_modified_changed,None)
  2293.         buff.connect("insert-text",self.on_text_buffer_insert_text,None)
  2294.         buff.connect("delete-range",self.on_text_buffer_delete_range,None)
  2295.         buff.connect("changed",self.on_text_buffer_changed,None)
  2296.         #buff.connect("mark-set",self.on_text_buffer_mark_set,None)
  2297.  
  2298.         # connect signals
  2299.         builder.connect_signals(self)
  2300.  
  2301.         # setup to accept file drags
  2302.         TARGET_TYPE_URI_LIST = 80
  2303.         dnd_list = [ ( 'text/uri-list', 0, TARGET_TYPE_URI_LIST ) ]
  2304.         #dnd_list = [("text/uri-list", 0, 25)]
  2305.         self.statusbar.drag_dest_set( gtk.DEST_DEFAULT_MOTION |
  2306.                   gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_DROP,
  2307.                   dnd_list, gtk.gdk.ACTION_COPY)
  2308.         #self.text_view.drag_dest_set(0, [], 0)
  2309.         self.statusbar.connect('drag_motion', self.on_drag_motion)
  2310.         #self.text_view.connect('drag_drop', self.on_drag_drop)
  2311.         self.statusbar.connect('drag_data_received', self.on_drag_data_received,None)
  2312.         self.statusbar.connect('drag_end', self.on_drag_end,None)
  2313.         #self.text_view.connect('drag_data_received', self.on_drag_data_received,None)
  2314.         #self.text_view.connect('drag_end', self.on_drag_end,None)
  2315.  
  2316.         # set the default icon to the GTK "edit" icon
  2317.         gtk.window_set_default_icon_name(gtk.STOCK_EDIT)
  2318.  
  2319.         # setup and initialize our statusbar
  2320.         self.statusbar_cid = self.statusbar.get_context_id("Edile GTK+ Text Editor")
  2321.  
  2322.         # setup search window
  2323.         self.search_window.set_destroy_with_parent(True)
  2324.         self.search_window.set_transient_for(self.window)
  2325.         self.search_window.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
  2326.         self.search_window.set_title('Find | Edile Text Editor')
  2327.         self.search_window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
  2328.  
  2329.         ###
  2330.         # load plugins
  2331.         ###
  2332.  
  2333.         self.load_plugins()
  2334.  
  2335.         # figure out what to put in the window and set the filename to
  2336.         should_load_default_file = (CONF_DEFAULT_FILE != "")
  2337.  
  2338.         # open file from command line or stdin/pipe
  2339.         if len(args) > 0:
  2340.             # first file from command line
  2341.             self.filename = args[0]
  2342.             # don't load the default document
  2343.             should_load_default_file = False
  2344.  
  2345.             if len(args) > 2:
  2346.                 # there are other filenames. spawn instances for them
  2347.                 other_filenames = sys.argv[2:]
  2348.                 [self.spawn(other_file) for other_file in other_filenames]
  2349.  
  2350.             if os.path.exists(self.filename):
  2351.                 # open first file
  2352.                 self.load_file(self.filename)
  2353.             else:
  2354.                 # file doesn't exist. create it on save.
  2355.                 self.reset_default_status()
  2356.  
  2357.                 # let user know what's going on
  2358.                 if os.access(os.path.dirname(self.filename),os.W_OK):
  2359.                     print "\nfile %s will be created."%(self.filename)
  2360.                 else:
  2361.                     print "\nfile %s not writable!"%(self.filename)
  2362.  
  2363.  
  2364.         if not sys.stdin.isatty():
  2365.             # open from pipe
  2366.             #self.filename = None
  2367.             #^you can log output this way
  2368.             buffer = self.text_view.get_buffer()
  2369.             buffer.set_text(sys.stdin.read())
  2370.             # move insertion point and scroll to top
  2371.             buffer.place_cursor(buffer.get_start_iter())
  2372.             self.reset_default_status()
  2373.         else:
  2374.             # open default document if appropriate
  2375.             if should_load_default_file:
  2376.                 if (os.path.exists(CONF_DEFAULT_FILE)) & (os.access(CONF_DEFAULT_FILE,os.W_OK)):
  2377.                     self.load_file(CONF_DEFAULT_FILE)
  2378.                 else:
  2379.                     print "\n%s doesn't exist. not opening\n"%(CONF_DEFAULT_FILE)
  2380.                     self.reset_default_status()
  2381.             else:
  2382.                 self.reset_default_status()
  2383.  
  2384.  
  2385.  
  2386.         #tv_dnd_list = self.text_view.drag_dest_get_target_list()
  2387.  
  2388.         #tv_dnd_list.extend(dnd_list)
  2389.         #self.text_view.drag_dest_set_target_list(tv_dnd_list)
  2390.  
  2391.     # Run main application window
  2392.     def main(self):
  2393.         self.window.show_all()
  2394.         gtk.main()
  2395.  
  2396. if __name__ == "__main__":
  2397.     editor = Edile()
  2398.     editor.main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement