29
29
from pida.pidagtk import contentview
30
30
from pida.core import actions
31
31
from pida.core import service
32
from pida.utils.culebra import edit, sensitive, common
32
from pida.utils.culebra import edit, sensitive, common, interfaces
35
34
defs = service.definitions
39
C = gtk.gdk.CONTROL_MASK
40
SC = gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK
36
from pida.model import attrtypes as types
38
from gtk import keysyms
39
from gtk.gdk import CONTROL_MASK, SHIFT_MASK
41
control = lambda x: (getattr(keysyms, x), CONTROL_MASK)
42
control_shift = lambda x: (getattr(keysyms, x), CONTROL_MASK|SHIFT_MASK)
43
'DocumentSave': (115, C),
44
'documenttypes+document+undo': (122, C),
45
'documenttypes+document+redo': (122, SC),
46
'documenttypes+document+cut': (120, C),
47
'documenttypes+document+copy': (99, C),
48
'documenttypes+document+paste': (118, C),
45
'DocumentSave': control("s"),
46
'documenttypes+document+undo': control("z"),
47
'documenttypes+document+redo': control_shift("z"),
48
'documenttypes+document+cut': control("x"),
49
'documenttypes+document+copy': control("c"),
50
'documenttypes+document+paste': control("v"),
51
'culebraedit+cut_line': control("d"),
52
'culebraedit+select_line': control("l"),
53
'culebraedit+select_word': control("h"),
54
'culebraedit+cut_word': control("j"),
55
'culebraedit+select_sentence': control("i"),
56
'culebraedit+cut_sentence': control("u"),
57
'culebraedit+select_paragraph': control("p"),
51
class culebra_view(contentview.content_view):
60
del control, control_shift
62
class CulebraView(contentview.content_view):
53
64
HAS_CONTROL_BOX = False
56
def init(self, filename=None, action_group=None, background_color=None, font_color=None):
67
def init(self, action_group=None, background_color=None,
68
font_color=None, font_text=None, document=None):
57
69
self.widget.set_no_show_all(True)
58
widget, editor = edit.create_widget(filename, action_group)
59
editor.set_background_color(background_color)
60
editor.set_font_color(font_color)
61
self.__editor = editor
62
self.buffer.connect('can-undo', self.cb_can_undo)
63
self.buffer.connect('can-redo', self.cb_can_redo)
65
self.widget.add(widget)
70
editor = property(get_editor)
73
return self.__editor.get_buffer()
75
buffer = property(get_buffer)
71
self.provider = edit.create_editor(action_group=action_group)
74
self.set_action_group = self.provider.get_service(interfaces.IActionGroupController).set_action_group
76
self.editor = self.provider.get_service('view')
77
self.buffer = self.editor.get_buffer()
78
# editor.set_background_color(background_color)
79
# editor.set_font_color(font_color)
80
self.editor.set_font(font_text)
81
# self.__editor = editor
83
self.buffer.connect('can-undo', self.cb_can_undo)
84
self.buffer.connect('can-redo', self.cb_can_redo)
86
# In this case we are not dealling with sourceview
88
file_ops = self.provider.get_service(interfaces.IFileOperations)
89
file_ops.set_encoding(document.encoding)
90
file_ops.set_filename(document.filename)
91
file_ops.set_mimetype(document.mimetype)
93
self._real_widget.show()
94
self.widget.add(self._real_widget)
96
_real_widget = property(lambda self: self.provider.get_service(interfaces.IWidget))
98
def get_file_ops(self):
99
return self.provider.get_service(interfaces.IFileOperations)
101
def get_carret(self):
102
return self.provider.get_service(interfaces.ICarretController)
77
104
def can_undo(self):
78
105
return self.buffer.can_undo()
87
114
self.service.cb_can_redo(self, can)
89
116
def connect_keys(self):
90
self.__editor.add_events(gtk.gdk.KEY_PRESS_MASK)
91
self.__editor.connect('key-press-event', self.cb_keypress)
117
self._real_widget.add_events(gtk.gdk.KEY_PRESS_MASK)
118
self._real_widget.connect('key-press-event', self.cb_keypress)
93
120
def cb_keypress(self, widg, event):
94
121
key, mod = event.keyval, event.state
95
122
return self.service.received_key(key, mod)
125
__order__ = ['general']
126
class general(defs.optiongroup):
127
"""Options for the culebra text editor"""
129
class font(defs.option):
130
"""Change the font used in Culebra."""
132
default = 'monospace 12'
135
def __markup__(self):
136
return 'Culebra text editor'
98
139
class culebra_editor(service.service):
100
141
display_name = 'Culebra Text Editor'
102
multi_view_type = culebra_view
103
multi_view_book = 'edit'
143
config_definition = CulebraConfig
145
class Culebra(defs.View):
146
view_type = CulebraView
105
class general(defs.optiongroup):
106
class background_color(defs.option):
107
"""Change the background color"""
111
class font_color(defs.option):
112
"""Change the font color"""
117
150
# Service related methods
152
self.__documents = {}
121
153
self.__views = {}
122
154
self.__keymods = {}
123
155
self.__undoacts = {}
156
self._save_action = None
159
def get_sanity_errors(cls):
160
"""No sanity checks are needed"""
127
for view in self.__files.values():
128
view.editor.set_background_color(self.get_background_color())
129
view.editor.set_font_color(self.get_font_color())
133
def get_background_color(self):
134
color = self.opt("general", "background_color")
135
return gdk.color_parse(color)
137
def get_font_color(self):
138
color = self.opt("general", "font_color")
139
return gdk.color_parse(color)
141
def __load_file(self, filename):
142
view = self.create_multi_view(
144
action_group=self.action_group,
145
background_color = self.get_background_color(),
146
font_color = self.get_font_color(),
148
self.__files[filename] = view
149
self.__views[view.unique_id] = filename
152
def __view_file(self, filename):
153
self.current_view = self.__files[filename]
154
self.__files[filename].raise_page()
160
def _get_actions(self):
161
actions = self.boss.call_command("documenttypes", "get_document_actions")
162
for action in actions:
164
self.__bind_document_actions()
167
def cb_general__font(self, font):
169
for view in self.__views.values():
170
view.editor.set_font(font)
171
except AttributeError:
174
def __bind_document_actions(self):
175
doctypes = self.boss.get_service("documenttypes")
176
for action in doctypes.cmd_get_document_actions():
163
177
actname = action.get_name()
164
178
if actname in KEYMAP:
165
179
self.__keymods[KEYMAP[actname]] = action
171
185
self.__revertact = action
172
186
elif actname == 'DocumentSave':
173
187
self._save_action = action
188
for act in self.action_group.list_actions():
189
actname = act.get_name()
190
if actname in KEYMAP:
191
self.__keymods[KEYMAP[actname]] = act
193
def __load_document(self, document):
194
view = self.create_view('Culebra',
195
action_group=self.action_group,
196
background_color = None,
198
font_text = self.opts.general__font,
201
self.__views[document.unique_id] = view
202
self.__documents[view.unique_id] = document
204
self.show_view(view=view)
206
def __view_document(self, document):
207
view = self.__views[document.unique_id]
209
# Use subscription pattern
210
if self.current_view is not None:
211
self.current_view.set_action_group(None)
213
self.current_view = view
214
self.__set_action_sensitivities(document)
216
def __set_action_sensitivities(self, document):
217
save_action = self.get_save_action()
219
save_action.set_sensitive(True)
220
self.__revertact.set_sensitive(False)
223
buff = self.current_view.editor.get_buffer()
224
self.current_view.set_action_group(self.action_group)
226
self.linker = sensitive.SaveLinker(buff, save_action)
227
self.linker2 = sensitive.SaveLinker(buff, self.__revertact)
229
self.cb_can_undo(self.current_view, self.current_view.can_undo())
230
self.cb_can_redo(self.current_view, self.current_view.can_redo())
232
def get_background_color(self):
233
color = self.opts.general__background_color
234
return gdk.color_parse(color)
236
def get_font_color(self):
237
color = self.opts.general__font_color
238
return gdk.color_parse(color)
175
240
def get_save_action(self):
176
if self._save_action is None:
241
#if self._save_action is None:
242
# self._get_actions()
178
243
return self._save_action
245
def get_window(self):
246
return self.boss.get_main_window()
180
248
# keyboard bindings
182
250
def received_key(self, key, mod):
251
# make sure we have no extra mods
252
mod &= (CONTROL_MASK | SHIFT_MASK)
183
253
if (key, mod) in self.__keymods:
184
254
self.__keymods[key, mod].emit('activate')
189
def get_window(self):
190
return self.boss.get_main_window()
204
271
current_view = None
205
def cmd_edit(self, filename=None):
206
if self.current_view is not None:
207
self.current_view.editor.set_action_group(None)
208
if filename not in self.__files:
209
self.__load_file(filename)
210
self.__view_file(filename)
211
save_action = self.get_save_action()
212
assert save_action is not None
213
buff = self.current_view.editor.get_buffer()
214
self.current_view.editor.set_action_group(self.action_group)
215
self.linker = sensitive.SaveLinker(buff, save_action)
216
self.linker2 = sensitive.SaveLinker(buff, self.__revertact)
218
self.cb_can_undo(self.current_view, self.current_view.can_undo())
219
self.cb_can_redo(self.current_view, self.current_view.can_redo())
272
def cmd_edit(self, document):
273
# temporary to preserve old filename behaviour
274
#filename = document.filename
275
#if self.current_view is not None:
276
# self.current_view.editor.set_action_group(None)
277
if document.unique_id not in self.__views:
278
self.__load_document(document)
279
self.__view_document(document)
281
def _file_op(self, oper, attr, label):
283
getattr(oper, attr)()
286
hig.error("There was an error trying to %s the document" % label,
287
str(err), parent=self.get_window())
221
290
def cmd_revert(self):
222
291
if self.current_view is None:
225
buff = self.current_view.editor.get_buffer()
294
buff = self.current_view.get_file_ops()
296
if buff.get_is_new():
229
299
# Ok the buffer is not new and exists
230
reply = hig.dialog_ok_cancel(
300
reply = hig.ok_cancel(
231
301
"Revert the document to saved contents",
232
302
("Even if your document was just saved it could be altered by a "
233
303
"third party. By reverting to its real contents you will loose "
235
305
parent = self.get_window(),
236
306
ok_button = gtk.STOCK_REVERT_TO_SAVED,
238
if reply == gtk.RESPONSE_OK:
239
buff.load_from_file()
308
if reply == gtk.RESPONSE_OK and self._file_op(buff, "load", "revert"):
240
309
self.boss.call_command('buffermanager', 'reset_current_document')
242
312
def cmd_start(self):
243
313
self.get_service('editormanager').events.emit('started')
245
315
def cmd_goto_line(self, linenumber):
246
view = self.current_view.editor
247
buff = self.current_view.buffer
250
line_iter = buff.get_iter_at_line(linenumber - 1)
251
# Move scroll to the line iterator
252
view.scroll_to_iter(line_iter, 0.25)
253
# Place the cursor at the begining of the line
254
buff.place_cursor(line_iter)
316
if self.current_view is None:
318
carret = self.current_view.get_carret()
319
carret.goto_line(linenumber - 1)
256
321
def cmd_save(self):
257
self.current_view.buffer.save()
258
self.boss.call_command('buffermanager', 'reset_current_document')
322
file_ops = self.current_view.get_file_ops()
323
if self._file_op(file_ops, "save", "save"):
324
self.boss.call_command('buffermanager', 'reset_current_document')
326
def cmd_save_as(self, filename):
327
buf = self.current_view.get_file_ops()
328
old_filename = buf.get_filename()
329
buf.set_filename(filename)
330
if not self._file_op(buf, "save", "save"):
331
buf.set_filename(old_filename)
260
333
def cmd_undo(self):
261
334
self.current_view.editor.emit('undo')
272
345
def cmd_paste(self):
273
346
self.current_view.editor.emit('paste-clipboard')
275
def cmd_close(self, filename):
276
# example implementation
277
view = self.__files[filename]
278
if self.confirm_multi_view_controlbar_clicked_close(view):
280
self.cb_multi_view_closed(view)
348
def cmd_close(self, document):
349
view = self.__views[document.unique_id]
350
#view = self.current_view
351
self.close_view(view)
352
self.current_view = None
282
354
def cmd_can_close(self):
283
buffs = [view.buffer for view in self.__files.values() if view.buffer.get_modified()]
355
buffs = map(lambda val: val.get_file_ops(), self.__views.values())
356
buffs = filter(lambda val: val.get_modified(), buffs)
284
358
# If we have no buffers to save, go on
285
359
if len(buffs) == 0:
288
filenames = dict(map(lambda buff: (buff.filename, buff), buffs))
362
filenames = dict(map(lambda buff: (buff.get_filename(), buff), buffs))
289
363
parent = self.get_window()
290
364
files, response = hig.save_changes(filenames.keys(), parent=parent)
291
365
# Save the files that need to be saved
292
367
for filename in files:
293
368
# XXX: handle new files
294
filenames[filename].save()
370
filenames[filename].save()
372
errors.append(filename)
295
376
return response in (gtk.RESPONSE_CLOSE, gtk.RESPONSE_OK)
378
def cmd_select_line(self):
379
buf = self.current_view.editor.get_buffer()
380
si = buf.get_iter_at_mark(buf.get_insert())
382
si.set_line_offset(0)
384
buf.select_range(si, ei)
386
def cmd_cut_line(self):
387
self.cmd_select_line()
390
def cmd_select_word(self):
391
buf = self.current_view.editor.get_buffer()
392
si = buf.get_iter_at_mark(buf.get_insert())
395
if not si.starts_word():
396
si.backward_word_start()
397
if not ei.ends_word():
398
ei.forward_word_end()
399
buf.select_range(si, ei)
404
def cmd_cut_word(self):
405
if self.cmd_select_word():
408
def cmd_select_sentence(self):
409
buf = self.current_view.editor.get_buffer()
410
si = buf.get_iter_at_mark(buf.get_insert())
411
if si.inside_sentence():
413
if not si.starts_sentence():
414
si.backward_sentence_start()
415
if not ei.ends_sentence():
416
ei.forward_sentence_end()
417
buf.select_range(si, ei)
422
def cmd_cut_sentence(self):
423
if self.cmd_select_sentence():
426
def cmd_select_paragraph(self):
427
buf = self.current_view.editor.get_buffer()
428
si = buf.get_iter_at_mark(buf.get_insert())
429
if not si.get_chars_in_line() > 1:
432
while si.get_chars_in_line() > 1 and not si.is_start():
434
si.set_line_offset(0)
435
if not si.is_start():
437
while ei.get_chars_in_line() > 1 and not ei.is_end():
439
buf.select_range(si, ei)
299
def cb_multi_view_closed(self, view):
300
if view.unique_id in self.__views:
301
filename = self.__views[view.unique_id]
302
del self.__views[view.unique_id]
303
del self.__files[filename]
304
self.boss.call_command('buffermanager', 'file_closed',
443
def view_closed(self, view):
444
if view.unique_id in self.__documents:
445
doc = self.__documents[view.unique_id]
446
del self.__documents[view.unique_id]
447
del self.__views[doc.unique_id]
448
self.boss.call_command('buffermanager', 'document_closed',
307
def confirm_multi_view_controlbar_clicked_close(self, view):
451
def view_confirm_close(self, view):
452
buff = view.get_file_ops()
310
454
# If buffer was not modified you can safely close it
311
455
if not buff.get_modified():
419
565
def act_replace_all(self, action):
420
566
"""Replaces all matching words"""
568
def act_select_line(self, action):
569
self.cmd_select_line()
571
def act_cut_line(self, action):
574
def act_select_word(self, action):
575
self.cmd_select_word()
577
def act_cut_word(self, action):
580
def act_select_sentence(self, action):
581
self.cmd_select_sentence()
583
def act_cut_sentence(self, action):
584
self.cmd_cut_sentence()
586
def act_select_paragraph(self, action):
587
self.cmd_select_paragraph()
424
590
Service = culebra_editor