~doctormo/python-snippets/lp-merge-request-example

« back to all changes in this revision

Viewing changes to pygtksourceview/test-widget.py

  • Committer: Jono Bacon
  • Date: 2009-12-31 04:35:06 UTC
  • Revision ID: jono@ubuntu.com-20091231043506-y5tdq5ahrv9fpecz
Added PyGTKSourceView example.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
# -*- coding: UTF-8 -*-
 
3
#
 
4
# [SNIPPET_NAME: GtkSourceView Example]
 
5
# [SNIPPET_CATEGORIES: PyGTK, PyGTKSourceView]
 
6
# [SNIPPET_DESCRIPTION: Demonstrates using Actions with a gtk.Action and gtk.AccelGroup]
 
7
#
 
8
# This script shows the use of pygtksourceview module, the python wrapper
 
9
# of gtksourceview C library.
 
10
# It has been directly translated from test-widget.c
 
11
#
 
12
# Copyright (C) 2004 - Iñigo Serna <inigoserna@telefonica.net>
 
13
#
 
14
# This program is free software; you can redistribute it and/or modify
 
15
# it under the terms of the GNU General Public License as published by
 
16
# the Free Software Foundation; either version 2 of the License, or
 
17
# (at your option) any later version.
 
18
 
19
# This program is distributed in the hope that it will be useful,
 
20
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
22
# GNU General Public License for more details.
 
23
#
 
24
# You should have received a copy of the GNU General Public License
 
25
# along with this program; if not, write to the Free Software
 
26
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
27
 
 
28
 
 
29
import os, os.path
 
30
import sys
 
31
import pygtk
 
32
pygtk.require ('2.0')
 
33
 
 
34
import gtk
 
35
if gtk.pygtk_version < (2,3,93):
 
36
    print "PyGtk 2.3.93 or later required for this example"
 
37
    raise SystemExit
 
38
 
 
39
import gtksourceview
 
40
import gnome.vfs
 
41
import pango
 
42
import gnomeprint.ui
 
43
 
 
44
 
 
45
######################################################################
 
46
##### global vars
 
47
windows = []    # this list contains all view windows
 
48
MARKER_TYPE_1 = 'one'
 
49
MARKER_TYPE_2 = 'two'
 
50
DATADIR = '/usr/share'
 
51
 
 
52
 
 
53
######################################################################
 
54
##### error dialog
 
55
def error_dialog(parent, msg):
 
56
    dialog = gtk.MessageDialog(parent,
 
57
                               gtk.DIALOG_DESTROY_WITH_PARENT,
 
58
                               gtk.MESSAGE_ERROR,
 
59
                               gtk.BUTTONS_OK,
 
60
                               msg)
 
61
    dialog.run()
 
62
    dialog.destroy()
 
63
    
 
64
 
 
65
######################################################################
 
66
##### remove all markers
 
67
def remove_all_markers(buffer):
 
68
    begin, end = buffer.get_bounds()
 
69
    markers = buffer.get_markers_in_region(begin, end)
 
70
    map(buffer.delete_marker, markers)
 
71
 
 
72
 
 
73
######################################################################
 
74
##### load file
 
75
def load_file(buffer, uri):
 
76
    buffer.begin_not_undoable_action()
 
77
    # TODO: use g_io_channel when pygtk supports it
 
78
    try:
 
79
        txt = open(uri.path).read()
 
80
    except:
 
81
        return False
 
82
    buffer.set_text(txt)
 
83
    buffer.set_data('filename', uri.path)
 
84
    buffer.end_not_undoable_action()
 
85
 
 
86
    buffer.set_modified(False)
 
87
    buffer.place_cursor(buffer.get_start_iter())
 
88
    return True
 
89
 
 
90
 
 
91
######################################################################
 
92
##### buffer creation
 
93
def open_file(buffer, filename):
 
94
    # get the new language for the file mimetype
 
95
    manager = buffer.get_data('languages-manager')
 
96
 
 
97
    if os.path.isabs(filename):
 
98
        path = filename
 
99
    else:
 
100
        path = os.path.abspath(filename)
 
101
    uri = gnome.vfs.URI(path)
 
102
 
 
103
    mime_type = gnome.vfs.get_mime_type(path) # needs ASCII filename, not URI
 
104
    if mime_type:
 
105
        language = manager.get_language_from_mime_type(mime_type)
 
106
        if language:
 
107
            buffer.set_highlight(True)
 
108
            buffer.set_language(language)
 
109
        else:
 
110
            print 'No language found for mime type "%s"' % mime_type
 
111
            buffer.set_highlight(False)
 
112
    else:
 
113
        print 'Couldn\'t get mime type for file "%s"' % filename
 
114
        buffer.set_highlight(False)
 
115
 
 
116
    remove_all_markers(buffer)
 
117
    load_file(buffer, uri) # TODO: check return
 
118
    return True
 
119
 
 
120
 
 
121
######################################################################
 
122
##### Printing callbacks
 
123
def page_cb(job, *args):
 
124
    percent = 100 * job.get_page() / job.get_page_count()
 
125
    print 'Printing %.2f%%    \r' % percent,
 
126
 
 
127
 
 
128
def finished_cb(job, *args):
 
129
    print
 
130
    gjob = job.get_print_job()
 
131
    preview = gnomeprint.ui.JobPreview(gjob, 'PyGtkSourceView Demo Print Preview')
 
132
    preview.show()
 
133
 
 
134
 
 
135
######################################################################
 
136
##### Action callbacks
 
137
def numbers_toggled_cb(action, sourceview):
 
138
    sourceview.set_show_line_numbers(action.get_active())
 
139
    
 
140
 
 
141
def markers_toggled_cb(action, sourceview):
 
142
    sourceview.set_show_line_markers(action.get_active())
 
143
    
 
144
 
 
145
def margin_toggled_cb(action, sourceview):
 
146
    sourceview.set_show_margin(action.get_active())
 
147
    
 
148
 
 
149
def auto_indent_toggled_cb(action, sourceview):
 
150
    sourceview.set_auto_indent(action.get_active())
 
151
    
 
152
 
 
153
def insert_spaces_toggled_cb(action, sourceview):
 
154
    sourceview.set_insert_spaces_instead_of_tabs(action.get_active())
 
155
    
 
156
 
 
157
def tabs_toggled_cb(action, action2, sourceview):
 
158
    sourceview.set_tabs_width(action.get_current_value())
 
159
    
 
160
 
 
161
def new_view_cb(action, sourceview):
 
162
    window = create_view_window(sourceview.get_buffer(), sourceview)
 
163
    window.set_default_size(400, 400)
 
164
    window.show()
 
165
    
 
166
 
 
167
def print_preview_cb(action, sourceview):
 
168
    buffer = sourceview.get_buffer()
 
169
    job = gtksourceview.SourcePrintJob()
 
170
    job.setup_from_view(sourceview)
 
171
    job.set_wrap_mode(gtk.WRAP_CHAR)
 
172
    job.set_highlight(True)
 
173
    job.set_print_numbers(5)
 
174
    job.set_header_format('Printed on %A', None, '%F', False)
 
175
    filename = buffer.get_data('filename')
 
176
    job.set_footer_format('%T', filename, 'Page %N/%Q', True)
 
177
    job.set_print_header(True)
 
178
    job.set_print_footer(True)
 
179
    start, end = buffer.get_bounds()
 
180
    if job.print_range_async(start, end):
 
181
        job.connect('begin_page', page_cb)
 
182
        job.connect('finished', finished_cb)
 
183
    else:
 
184
        print 'Async print failed'
 
185
 
 
186
 
 
187
######################################################################
 
188
##### Buffer action callbacks
 
189
def open_file_cb(action, buffer):
 
190
    chooser = gtk.FileChooserDialog('Open file...', None,
 
191
                                    gtk.FILE_CHOOSER_ACTION_OPEN,
 
192
                                    (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
 
193
                                    gtk.STOCK_OPEN, gtk.RESPONSE_OK))
 
194
    response = chooser.run()
 
195
    if response == gtk.RESPONSE_OK:
 
196
        filename = chooser.get_filename()
 
197
        if filename:
 
198
            open_file(buffer, filename)
 
199
    chooser.destroy()
 
200
 
 
201
 
 
202
def update_cursor_position(buffer, view):
 
203
    tabwidth = view.get_tabs_width()
 
204
    pos_label = view.get_data('pos_label')
 
205
    iter = buffer.get_iter_at_mark(buffer.get_insert())
 
206
    nchars = iter.get_offset()
 
207
    row = iter.get_line() + 1
 
208
    start = iter
 
209
    start.set_line_offset(0)
 
210
    col = 0
 
211
    while not start.equal(iter):
 
212
        if start.get_char == '\t':
 
213
            col += (tabwidth - (col % tabwidth))
 
214
        else:
 
215
            col += 1
 
216
            start = start.forward_char()
 
217
    pos_label.set_text('char: %d, line: %d, column: %d' % (nchars, row, col))
 
218
    
 
219
 
 
220
def move_cursor_cb (buffer, cursoriter, mark, view):
 
221
    update_cursor_position(buffer, view)
 
222
 
 
223
 
 
224
def window_deleted_cb(widget, ev, view):
 
225
    if windows[0] == widget:
 
226
        gtk.main_quit()
 
227
    else:
 
228
        # remove window from list
 
229
        windows.remove(widget)
 
230
        # we return False since we want the window destroyed
 
231
        return False
 
232
    return True
 
233
 
 
234
 
 
235
def button_press_cb(view, ev):
 
236
    buffer = view.get_buffer()
 
237
    if not view.get_show_line_markers():
 
238
        return False
 
239
    # check that the click was on the left gutter
 
240
    if ev.window == view.get_window(gtk.TEXT_WINDOW_LEFT):
 
241
        if ev.button == 1:
 
242
            marker_type = MARKER_TYPE_1
 
243
        else:
 
244
            marker_type = MARKER_TYPE_2
 
245
        x_buf, y_buf = view.window_to_buffer_coords(gtk.TEXT_WINDOW_LEFT,
 
246
                                                    int(ev.x), int(ev.y))
 
247
        # get line bounds
 
248
        line_start = view.get_line_at_y(y_buf)[0]
 
249
        line_end = line_start.copy()
 
250
        line_end.forward_to_line_end()
 
251
 
 
252
        # get the markers already in the line
 
253
        marker_list = buffer.get_markers_in_region(line_start, line_end)
 
254
        # search for the marker corresponding to the button pressed
 
255
        for m in marker_list:
 
256
            if m.get_marker_type() == marker_type:
 
257
                marker = m
 
258
                break
 
259
        else:
 
260
            marker = None
 
261
 
 
262
        if marker:
 
263
            # a marker was found, so delete it
 
264
            buffer.delete_marker(marker)
 
265
        else:
 
266
            # no marker found, create one
 
267
            marker = buffer.create_marker(None, marker_type, line_start)
 
268
    return False
 
269
        
 
270
 
 
271
######################################################################
 
272
##### Actions & UI definition
 
273
buffer_actions = [
 
274
    ('Open', gtk.STOCK_OPEN, '_Open', '<control>O', 'Open a file', open_file_cb),
 
275
    ('Quit', gtk.STOCK_QUIT, '_Quit', '<control>Q', 'Exit the application', gtk.main_quit)
 
276
]
 
277
 
 
278
view_actions = [
 
279
    ('FileMenu', None, '_File'),
 
280
    ('ViewMenu', None, '_View'),
 
281
    ('PrintPreview', gtk.STOCK_PRINT, '_Print Preview', '<control>P', 'Preview printing of the file', print_preview_cb),
 
282
    ('NewView', gtk.STOCK_NEW, '_New View', None, 'Create a new view of the file', new_view_cb),
 
283
    ('TabsWidth', None, '_Tabs Width')
 
284
]
 
285
 
 
286
toggle_actions = [
 
287
    ('ShowNumbers', None, 'Show _Line Numbers', None, 'Toggle visibility of line numbers in the left margin', numbers_toggled_cb, False),
 
288
    ('ShowMarkers', None, 'Show _Markers', None, 'Toggle visibility of markers in the left margin', markers_toggled_cb, False),
 
289
    ('ShowMargin', None, 'Show M_argin', None, 'Toggle visibility of right margin indicator', margin_toggled_cb, False),
 
290
    ('AutoIndent', None, 'Enable _Auto Indent', None, 'Toggle automatic auto indentation of text', auto_indent_toggled_cb, False),
 
291
    ('InsertSpaces', None, 'Insert _Spaces Instead of Tabs', None, 'Whether to insert space characters when inserting tabulations', insert_spaces_toggled_cb, False)
 
292
]
 
293
 
 
294
radio_actions = [
 
295
    ('TabsWidth4', None, '4', None, 'Set tabulation width to 4 spaces', 4),
 
296
    ('TabsWidth6', None, '6', None, 'Set tabulation width to 6 spaces', 6),
 
297
    ('TabsWidth8', None, '8', None, 'Set tabulation width to 8 spaces', 8),
 
298
    ('TabsWidth10', None, '10', None, 'Set tabulation width to 10 spaces', 10),
 
299
    ('TabsWidth12', None, '12', None, 'Set tabulation width to 12 spaces', 12)
 
300
]
 
301
 
 
302
view_ui_description = """
 
303
<ui>
 
304
  <menubar name='MainMenu'>
 
305
    <menu action='FileMenu'>
 
306
      <menuitem action='PrintPreview'/>
 
307
    </menu>
 
308
    <menu action='ViewMenu'>
 
309
      <menuitem action='NewView'/>
 
310
      <separator/>
 
311
      <menuitem action='ShowNumbers'/>
 
312
      <menuitem action='ShowMarkers'/>
 
313
      <menuitem action='ShowMargin'/>
 
314
      <separator/>
 
315
      <menuitem action='AutoIndent'/>
 
316
      <menuitem action='InsertSpaces'/>
 
317
      <separator/>
 
318
      <menu action='TabsWidth'>
 
319
        <menuitem action='TabsWidth4'/>
 
320
        <menuitem action='TabsWidth6'/>
 
321
        <menuitem action='TabsWidth8'/>
 
322
        <menuitem action='TabsWidth10'/>
 
323
        <menuitem action='TabsWidth12'/>
 
324
      </menu>
 
325
    </menu>
 
326
  </menubar>
 
327
</ui>
 
328
"""
 
329
 
 
330
buffer_ui_description = """
 
331
<ui>
 
332
  <menubar name='MainMenu'>
 
333
    <menu action='FileMenu'>
 
334
      <menuitem action='Open'/>
 
335
      <separator/>
 
336
      <menuitem action='Quit'/>
 
337
    </menu>
 
338
    <menu action='ViewMenu'>
 
339
    </menu>
 
340
  </menubar>
 
341
</ui>
 
342
"""
 
343
 
 
344
    
 
345
######################################################################
 
346
##### create view window
 
347
def create_view_window(buffer, sourceview = None):
 
348
    # window
 
349
    window = gtk.Window(gtk.WINDOW_TOPLEVEL)
 
350
    window.set_border_width(0)
 
351
    window.set_title('PyGtkSourceView Demo')
 
352
    windows.append(window) # this list contains all view windows
 
353
 
 
354
    # view
 
355
    view = gtksourceview.SourceView(buffer)
 
356
    buffer.connect('mark_set', move_cursor_cb, view)
 
357
    buffer.connect('changed', update_cursor_position, view)
 
358
    view.connect('button-press-event', button_press_cb)
 
359
    window.connect('delete-event', window_deleted_cb, view)
 
360
 
 
361
    # action group and UI manager
 
362
    action_group = gtk.ActionGroup('ViewActions')
 
363
    action_group.add_actions(view_actions, view)
 
364
    action_group.add_toggle_actions(toggle_actions, view)
 
365
    action_group.add_radio_actions(radio_actions, -1, tabs_toggled_cb, view)
 
366
 
 
367
    ui_manager = gtk.UIManager()
 
368
    ui_manager.insert_action_group(action_group, 0)
 
369
    # save a reference to the ui manager in the window for later use
 
370
    window.set_data('ui_manager', ui_manager)
 
371
    accel_group = ui_manager.get_accel_group()
 
372
    window.add_accel_group(accel_group)
 
373
    ui_manager.add_ui_from_string(view_ui_description)
 
374
 
 
375
    # misc widgets
 
376
    vbox = gtk.VBox(0, False)
 
377
    sw = gtk.ScrolledWindow()
 
378
    sw.set_shadow_type(gtk.SHADOW_IN)
 
379
    pos_label = gtk.Label('Position')
 
380
    view.set_data('pos_label', pos_label)
 
381
    menu = ui_manager.get_widget('/MainMenu')
 
382
 
 
383
    # layout widgets
 
384
    window.add(vbox)
 
385
    vbox.pack_start(menu, False, False, 0)
 
386
    vbox.pack_start(sw, True, True, 0)
 
387
    sw.add(view)
 
388
    vbox.pack_start(pos_label, False, False, 0)
 
389
 
 
390
    # setup view
 
391
    font_desc = pango.FontDescription('monospace 10')
 
392
    if font_desc:
 
393
        view.modify_font(font_desc)
 
394
 
 
395
    # change view attributes to match those of sourceview
 
396
    if sourceview:
 
397
        action = action_group.get_action('ShowNumbers')
 
398
        action.set_active(sourceview.get_show_line_numbers())
 
399
        action = action_group.get_action('ShowMarkers')
 
400
        action.set_active(sourceview.get_show_line_markers())
 
401
        action = action_group.get_action('ShowMargin')
 
402
        action.set_active(sourceview.get_margin())
 
403
        action = action_group.get_action('AutoIndent')
 
404
        action.set_active(sourceview.get_auto_indent())
 
405
        action = action_group.get_action('InsertSpaces')
 
406
        action.set_active(sourceview.get_insert_spaces_instead_of_tabs())
 
407
        action = action_group.get_action('TabsWidth%d' % sourceview.get_tabs_width())
 
408
        if action:
 
409
            action.set_active(True)
 
410
 
 
411
    # add marker pixbufs
 
412
    pixbuf = gtk.gdk.pixbuf_new_from_file(os.path.join(DATADIR,
 
413
                                                       'pixmaps/apple-green.png'))
 
414
    if pixbuf:
 
415
        view.set_marker_pixbuf(MARKER_TYPE_1, pixbuf)
 
416
    else:
 
417
        print 'could not load marker 1 image.  Spurious messages might get triggered'
 
418
    pixbuf = gtk.gdk.pixbuf_new_from_file(os.path.join(DATADIR,
 
419
                                                       'pixmaps/apple-red.png'))
 
420
    if pixbuf:
 
421
        view.set_marker_pixbuf(MARKER_TYPE_2, pixbuf)
 
422
    else:
 
423
        print 'could not load marker 2 image.  Spurious messages might get triggered'
 
424
 
 
425
    vbox.show_all()
 
426
 
 
427
    return window
 
428
    
 
429
    
 
430
######################################################################
 
431
##### create main window
 
432
def create_main_window(buffer):
 
433
    window = create_view_window(buffer)
 
434
    ui_manager = window.get_data('ui_manager')
 
435
    
 
436
    # buffer action group
 
437
    action_group = gtk.ActionGroup('BufferActions')
 
438
    action_group.add_actions(buffer_actions, buffer)
 
439
    ui_manager.insert_action_group(action_group, 1)
 
440
    # merge buffer ui
 
441
    ui_manager.add_ui_from_string(buffer_ui_description)
 
442
 
 
443
    # preselect menu checkitems
 
444
    groups = ui_manager.get_action_groups()
 
445
    # retrieve the view action group at position 0 in the list
 
446
    action_group = groups[0]
 
447
    action = action_group.get_action('ShowNumbers')
 
448
    action.set_active(True)
 
449
    action = action_group.get_action('ShowMarkers')
 
450
    action.set_active(True)
 
451
    action = action_group.get_action('ShowMargin')
 
452
    action.set_active(True)
 
453
    action = action_group.get_action('AutoIndent')
 
454
    action.set_active(True)
 
455
    action = action_group.get_action('InsertSpaces')
 
456
    action.set_active(True)
 
457
    action = action_group.get_action('TabsWidth8')
 
458
    action.set_active(True)
 
459
 
 
460
    return window
 
461
 
 
462
 
 
463
######################################################################
 
464
##### main
 
465
def main(args = []):
 
466
    # create buffer
 
467
    lm = gtksourceview.SourceLanguagesManager()
 
468
    buffer = gtksourceview.SourceBuffer()
 
469
    buffer.set_data('languages-manager', lm)
 
470
 
 
471
    # parse arguments
 
472
    if len(args) > 2:
 
473
        open_file(buffer, args[1])
 
474
    else:
 
475
        open_file(buffer, args[0])
 
476
        
 
477
    # create first window
 
478
    window = create_main_window(buffer)
 
479
    window.set_default_size(500, 500)
 
480
    window.show()
 
481
 
 
482
    # main loop
 
483
    gtk.main()
 
484
    
 
485
 
 
486
if __name__ == '__main__':
 
487
    if '--debug' in sys.argv:
 
488
        import pdb
 
489
        pdb.run('main(sys.argv)')
 
490
    else:
 
491
        main(sys.argv)