#!/usr/bin/env python # This is a sample implementation of an editor. import os import pygtk pygtk.require('2.0') import gtk import dialogs BLOCK_SIZE = 2048 RESPONSE_FORWARD = 1 class EditWindow(gtk.Window): def __init__(self, quit_cb=None): gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) self.set_size_request(470, 300) self.connect("delete_event", self.file_exit) self.quit_cb = quit_cb self.vbox = gtk.VBox() self.add(self.vbox) self.vbox.show() hdlbox = gtk.HandleBox() self.vbox.pack_start(hdlbox, expand=False) hdlbox.show() self.menubar, self.toolbar = self.create_menu() hdlbox.add(self.menubar) self.menubar.show() self.vbox.pack_start(self.toolbar, expand=False) self.scrolledwin = gtk.ScrolledWindow() self.scrolledwin.show() self.vbox.pack_start(self.scrolledwin) self.text = gtk.TextView() self.text.set_editable(True) self.scrolledwin.add(self.text) self.text.show() self.buffer = self.text.get_buffer() self.dirty = 0 self.file_new() self.text.grab_focus() self.clipboard = gtk.Clipboard(selection='CLIPBOARD') self.dirname = None self.search_string = None self.last_search_iter = None return def load_file(self, fname): try: fd = open(fname) self.buffer.set_text('') buf = fd.read(BLOCK_SIZE) while buf != '': self.buffer.insert_at_cursor(buf) buf = fd.read(BLOCK_SIZE) self.text.queue_draw() self.set_title(os.path.basename(fname)) self.fname = fname self.dirname = os.path.dirname(self.fname) self.buffer.set_modified(False) self.new = 0 except: dlg = gtk.MessageDialog(self, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, "Can't open " + fname) resp = dlg.run() dlg.hide() return def create_menu(self): ui_string = """ """ actions = [ ('FileMenu', None, '_File'), ('FileNew', gtk.STOCK_NEW, None, None, None, self.file_new), ('FileOpen', gtk.STOCK_OPEN, None, None, None, self.file_open), ('FileSave', gtk.STOCK_SAVE, None, None, None, self.file_save), ('FileSaveAs', gtk.STOCK_SAVE_AS, None, None, None, self.file_saveas), ('FileExit', gtk.STOCK_QUIT, None, None, None, self.file_exit), ('EditMenu', None, '_Edit'), ('EditCut', gtk.STOCK_CUT, None, None, None, self.edit_cut), ('EditCopy', gtk.STOCK_COPY, None, None, None, self.edit_copy), ('EditPaste', gtk.STOCK_PASTE, None, None, None, self.edit_paste), ('EditClear', gtk.STOCK_REMOVE, 'C_lear', None, None, self.edit_clear), ('EditFind', gtk.STOCK_FIND, None, None, None, self.edit_find), ('EditFindNext', None, 'Find _Next', "F3", None, self.edit_find_next), ('HelpMenu', gtk.STOCK_HELP), ('HelpAbout', None, 'A_bout', None, None, self.help_about), ] self.ag = gtk.ActionGroup('edit') self.ag.add_actions(actions) self.ui = gtk.UIManager() self.ui.insert_action_group(self.ag, 0) self.ui.add_ui_from_string(ui_string) self.add_accel_group(self.ui.get_accel_group()) return (self.ui.get_widget('/menubar'), self.ui.get_widget('/toolbar')) def chk_save(self): if self.buffer.get_modified(): dlg = gtk.Dialog('Unsaved File', self, gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_YES, gtk.RESPONSE_YES, gtk.STOCK_NO, gtk.RESPONSE_NO, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) lbl = gtk.Label((self.fname or "Untitled")+ " has not been saved\n" + "Do you want to save it?") lbl.show() dlg.vbox.pack_start(lbl) ret = dlg.run() dlg.hide() if ret == gtk.RESPONSE_NO: return 0 if ret == gtk.RESPONSE_YES: if self.file_save(): return 0 return 1 return 0 def file_new(self, mi=None): if self.chk_save(): return self.buffer.set_text('') self.buffer.set_modified(False) self.fname = None self.set_title("Untitled") self.new = 1 return def file_open(self, mi=None): if self.chk_save(): return fname = dialogs.OpenFile('Open File', self, self.dirname, self.fname) if not fname: return self.load_file(fname) return def file_save(self, mi=None): if self.new: return self.file_saveas() ret = False try: start, end = self.buffer.get_bounds() blockend = start.copy() fd = open(self.fname, "w") while blockend.forward_chars(BLOCK_SIZE): buf = self.buffer.get_text(start, blockend) fd.write(buf) start = blockend.copy() buf = self.buffer.get_text(start, blockend) fd.write(buf) fd.close() self.buffer.set_modified(False) ret = True except: dlg = gtk.MessageDialog(self, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, "Error saving file " + self.fname) resp = dlg.run() dlg.hide() return ret def file_saveas(self, mi=None): fname = dialogs.SaveFile('Save File As', self, self.dirname, self.fname) if not fname: return False self.fname = fname self.dirname = os.path.dirname(self.fname) self.set_title(os.path.basename(fname)) self.new = 0 return self.file_save() def file_exit(self, mi=None, event=None): if self.chk_save(): return True self.hide() self.destroy() if self.quit_cb: self.quit_cb(self) return False def edit_cut(self, mi): self.buffer.cut_clipboard(self.clipboard, True) return def edit_copy(self, mi): self.buffer.copy_clipboard(self.clipboard) return def edit_paste(self, mi): self.buffer.paste_clipboard(self.clipboard, None, True) return def edit_clear(self, mi): self.buffer.delete_selection(True, True) return def _search(self, search_string, iter = None): if iter is None: start = self.buffer.get_start_iter() else: start = iter i = 0 if search_string: self.search_string = search_string res = start.forward_search(search_string, gtk.TEXT_SEARCH_TEXT_ONLY) if res: match_start, match_end = res self.buffer.place_cursor(match_start) self.buffer.select_range(match_start, match_end) self.text.scroll_to_iter(match_start, 0.0) self.last_search_iter = match_end else: self.search_string = None self.last_search_iter = None def edit_find(self, mi): def dialog_response_callback(dialog, response_id): if response_id == gtk.RESPONSE_CLOSE: dialog.destroy() return self._search(search_text.get_text(), self.last_search_iter) search_text = gtk.Entry() s = self.buffer.get_selection_bounds() if len(s) > 0: search_text.set_text(self.buffer.get_slice(s[0], s[1])) dialog = gtk.Dialog("Search", self, gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_FIND, RESPONSE_FORWARD, gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)) dialog.vbox.pack_end(search_text, True, True, 0) dialog.connect("response", dialog_response_callback) search_text.show() search_text.grab_focus() dialog.show_all() response_id = dialog.run() def edit_find_next(self, mi): self._search(self.search_string, self.last_search_iter) def help_about(self, mi): dlg = gtk.MessageDialog(self, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, "Copyright (C)\n" "1998 James Henstridge\n" "2004 John Finlay\n" "This program is covered by the GPL>=2") dlg.run() dlg.hide() return def edit(fname, mainwin=False): if mainwin: quit_cb = lambda w: gtk.main_quit() else: quit_cb = None w = EditWindow(quit_cb=quit_cb) w.load_file(fname) w.show() w.set_size_request(0,0) if mainwin: gtk.main() return if __name__ == '__main__': import sys edit(sys.argv[-1], mainwin=True)