Ticket #2746: edit_app.py

File edit_app.py, 8.0 KB (added by walter, 13 years ago)

a version of Edit that supports old-style and new-style toolbars

Line 
1'''A simple text editor for Sugar
2Written mostly by Nate Theis
3Some GTK code borrowed from Pippy
4'''
5
6from groupthink import sugar_tools, gtk_tools
7
8from gettext import gettext as _
9
10import gtk
11import pango
12import time
13import gtksourceview2 as gtksourceview
14
15from sugar.activity import activity
16
17try:  # Can use 'New' toolbar design?
18    from sugar.graphics.toolbarbox import ToolbarBox
19    _HAVE_TOOLBOX = True
20except ImportError:
21    _HAVE_TOOLBOX = False
22
23if _HAVE_TOOLBOX:
24    from sugar.activity.widgets import ActivityToolbarButton, StopButton
25    from sugar.graphics.toolbarbox import ToolbarButton
26
27from sugar.graphics import style
28from sugar.activity.activity import EditToolbar
29
30import mdnames
31
32
33class EditActivity(sugar_tools.GroupActivity):
34    '''A text editor for Sugar
35    pylint says I need a docstring. Here you go.
36    '''
37
38    message_preparing = _("Loading...")
39    message_joining = _("Joining shared activity...")
40    message_loading = _("Reading journal entry...")
41
42    def checkts(self):
43        '''Check the timestamp
44        If someone's modified our file in an external editor,
45        we should reload the contents
46        '''
47
48        mtime = self.metadata[mdnames.sugartimestamp_md]
49        etime = self.metadata[mdnames.cloudtimestamp_md]
50        return mtime > etime
51
52    def __init__(self, handle):
53        '''We want to set up the buffer et al. early on
54        sure there's early_setup, but that's not early enough
55        '''
56
57        self.buffer = gtksourceview.Buffer()
58        self.refresh_buffer = False
59
60        self.text_view = gtksourceview.View(self.buffer)
61        self.scrollwindow = gtk.ScrolledWindow()
62
63        self.scrollwindow.add(self.text_view)
64
65        sugar_tools.GroupActivity.__init__(self, handle)
66
67    def fix_mimetype(self):
68        '''We must have a mimetype. Sometimes, we don't (when we get launched
69        newly.) This  fixes that.'''
70        if self.metadata[mdnames.mimetype_md] == '':
71            self.metadata[mdnames.mimetype_md] = "text/plain"
72            #we MUST have a mimetype
73
74    def setup_toolbar(self):
75        '''Setup the top toolbar. Groupthink needs some work here.'''
76
77        if _HAVE_TOOLBOX:  # 'New' Sugar toolbar design
78            toolbox = ToolbarBox()
79
80            activity_button = ActivityToolbarButton(self)
81            toolbox.toolbar.insert(activity_button, 0)
82            activity_button.show()
83
84            self.set_toolbar_box(toolbox)
85            toolbox.show()
86            toolbar = toolbox.toolbar
87
88            self.edit_toolbar = EditToolbar()
89            edit_toolbar_button = ToolbarButton(
90                page=self.edit_toolbar,
91                icon_name='toolbar-edit')
92            self.edit_toolbar.show()
93            toolbar.insert(edit_toolbar_button, -1)
94            edit_toolbar_button.show()
95
96        else:  # 'Old' Sugar toolbar design
97            self.edit_toolbar = EditToolbar()
98            toolbox = activity.ActivityToolbox(self)
99            self.set_toolbox(toolbox)
100            toolbox.add_toolbar(_('Edit'), self.edit_toolbar)
101            toolbox.show()
102            toolbox.set_current_toolbar(1)
103            toolbar = self.edit_toolbar
104
105        self.edit_toolbar.undo.connect('clicked', self.undobutton_cb)
106        self.edit_toolbar.redo.connect('clicked', self.redobutton_cb)
107        self.edit_toolbar.copy.connect('clicked', self.copybutton_cb)
108        self.edit_toolbar.paste.connect('clicked', self.pastebutton_cb)
109
110        if _HAVE_TOOLBOX:
111            separator = gtk.SeparatorToolItem()
112            separator.props.draw = False
113            separator.set_expand(True)
114            toolbar.insert(separator, -1)
115            separator.show()
116
117            stop_button = StopButton(self)
118            stop_button.props.accelerator = '<Ctrl>q'
119            toolbox.toolbar.insert(stop_button, -1)
120            stop_button.show()
121
122    def initialize_display(self):
123        '''Set up GTK and friends'''
124        self.fix_mimetype()
125
126        self.cloud.shared_buffer = gtk_tools.TextBufferSharePoint(self.buffer)
127
128        self.setup_toolbar()
129        #Some graphics code borrowed from Pippy
130
131        lang_manager = gtksourceview.language_manager_get_default()
132        if hasattr(lang_manager, 'list_languages'):
133            langs = lang_manager.list_languages()
134        else:
135            lang_ids = lang_manager.get_language_ids()
136            langs = [lang_manager.get_language(lang_id) \
137                         for lang_id in lang_ids]
138            for lang in langs:
139                for mtype in lang.get_mime_types():
140                    if mtype == self.metadata[mdnames.mimetype_md]:
141                        self.buffer.set_language(lang)
142                        break
143
144        self.text_view.set_editable(True)
145        self.text_view.set_cursor_visible(True)
146
147        if self.metadata[mdnames.mimetype_md] == "text/plain":
148            self.text_view.set_show_line_numbers(False)
149            self.text_view.set_wrap_mode(gtk.WRAP_WORD)
150            font = pango.FontDescription("Bitstream Vera Sans " +
151                                         str(style.FONT_SIZE))
152        else:
153            if hasattr(self.buffer, 'set_highlight'):
154                self.buffer.set_highlight(True)
155            else:
156                self.buffer.set_highlight_syntax(True)
157
158            self.text_view.set_show_line_numbers(True)
159
160            self.text_view.set_wrap_mode(gtk.WRAP_CHAR)
161            self.text_view.set_insert_spaces_instead_of_tabs(True)
162            self.text_view.set_tab_width(2)
163            self.text_view.set_auto_indent(True)
164            font = pango.FontDescription("Monospace " +
165                                         str(style.FONT_SIZE))
166
167        self.text_view.modify_font(font)
168
169        if self.refresh_buffer:
170            #see load_from_journal()
171            self.buffer.begin_not_undoable_action()
172            self.buffer.set_text(self.refresh_buffer)
173            self.buffer.end_not_undoable_action()
174
175        self.text_view.show()
176
177        #Return the main widget. our parents take care of GTK stuff
178        return self.scrollwindow
179
180    def save_to_journal(self, filename, cloudstring):
181        '''Saves to the journal.
182        We use metadata magic to keep the collab. stuff'''
183        self.metadata[mdnames.cloudstring_md] = cloudstring
184
185        #Also write to file:
186        fhandle = open(filename, "w")
187
188        bounds = self.buffer.get_bounds()
189        text = self.buffer.get_text(bounds[0], bounds[1])
190
191        fhandle.write(text)
192        fhandle.close()
193
194        self.fix_mimetype()
195
196        #We can do full-text search on all Edit documents, yay
197        self.metadata[mdnames.contents_md] = text
198
199        #If we edit the file in another way, we need to reload the contents
200        #we fudge the timestamp forwards by 5 seconds
201        #mmmm, fudge
202        self.metadata[mdnames.cloudtimestamp_md] = time.clock() + 5
203
204    def load_from_journal(self, filename):
205        '''Load the file. Duh.'''
206
207        if mdnames.cloudstring_md in self.metadata:
208            if self.checkts():
209                #if we were edited in another program
210                #we need to reload the text
211                #setting self.refresh_buffer makes us do that
212                text = open(filename, "r").read()  # yay hackish one-line read
213                self.refresh_buffer = text
214
215            #File has been saved with Edit, thus
216            #load the fancy collaboration data
217            #instead of just the text
218            return self.metadata[mdnames.cloudstring_md]
219
220        else:
221            text = open(filename, "r").read()  # yay hackish one-line read
222
223            self.buffer.set_text(text)
224            return None
225
226    def when_shared(self):
227        self._edit_toolbar.undo.set_sensitive(False)
228        self._edit_toolbar.redo.set_sensitive(False)
229
230    def undobutton_cb(self, button):
231        if self.buffer.can_undo():
232            self.buffer.undo()
233
234    def redobutton_cb(self, button):
235        global text_buffer
236        if self.buffer.can_redo():
237            self.buffer.redo()
238
239    def copybutton_cb(self, button):
240        self.buffer.copy_clipboard(gtk.Clipboard())
241
242    def pastebutton_cb(self, button):
243        self.buffer.paste_clipboard(gtk.Clipboard(), None, True)