39
### Atomic Save and Load Function
43
33
gettext.install('pyroom', 'locale')
35
from basic_edit import BasicEdit
37
from autosave import kill_tempfile
38
from autosave import set_autosave_time
39
from autosave import get_autosave_time
47
styles = {'darkgreen': {
49
'background': '#000000',
50
'foreground': '#007700',
54
'font': 'Droid Sans Mono',
60
'background': '#000000',
61
'foreground': '#0000FA',
65
'font': 'Droid Sans Mono',
69
}, 'amber' : { # integrated as reported from Marc Carson, Bug #189261 (i like it !!!)
71
'background' : '#151000',
72
'foreground' : '#AE8400',
76
'font' : 'DejaVu Sans Mono',
79
'size' : [0.45, 0.75] # [width, height]
82
'background': '#000000',
83
'foreground': '#00ff00',
87
'font': 'Droid Sans Mono',
93
'background': '#0000ff',
94
'foreground': '#ffffff',
98
'font': 'Droid Sans Mono',
104
FILE_UNNAMED = _('* Unnamed *')
107
_("""PyRoom - an adaptation of write room
108
Copyright (c) 2007 Nicolas Rougier, NoWhereMan
109
Copyright (c) 2008 Bruno Bord
110
Copyright (c) 2008 Marco Crosio
111
... The other Team Members goes here ...
113
This program is free software: you can redistribute it and/or modify it under
114
the terms of the GNU General Public License as published by the Free Software
115
Foundation, either version 3 of the License, or (at your option) any later
121
Usage: pyroom [-v] [--style={style name}] file1 file2
122
style can be either 'blue', 'green', 'darkgreen'
127
Control-H: Show help in a new buffer
128
Control-I: Show buffer information
129
Control-L: Toggle line number
130
Control-N: Create a new buffer
131
Control-O: Open a file in a new buffer
133
Control-S: Save current buffer
134
Control-Shift-S: Save current buffer as
135
Control-W: Close buffer and exit if it was the last buffer
136
Control-Y: Redo last typing
137
Control-Z: Undo last typing
138
Control-Page Up: Switch to previous buffer
139
Control-Page Down: Switch to next buffer
140
Control-Plus: Increases font size
141
Control-Minus: Decreases font size
145
No question whether to close a modified buffer or not
149
class FadeLabel(gtk.Label):
150
""" GTK Label with timed fade out effect """
152
active_duration = 3000 # Fade start after this time
153
fade_duration = 1500 # Fade duration
155
def __init__(self, message='', active_color=None, inactive_color=None):
156
gtk.Label.__init__(self, message)
158
active_color = '#ffffff'
159
self.active_color = active_color
160
if not inactive_color:
161
inactive_color = '#000000'
162
self.inactive_color = inactive_color
165
def set_text(self, message, duration=None):
167
duration = self.active_duration
168
self.modify_fg(gtk.STATE_NORMAL,
169
gtk.gdk.color_parse(self.active_color))
170
gtk.Label.set_text(self, message)
172
gobject.source_remove(self.idle)
173
self.idle = gobject.timeout_add(duration, self.fade_start)
175
def fade_start(self):
176
self.fade_level = 1.0
178
gobject.source_remove(self.idle)
179
self.idle = gobject.timeout_add(25, self.fade_out)
182
color = gtk.gdk.color_parse(self.inactive_color)
183
(red1, green1, blue1) = (color.red, color.green, color.blue)
184
color = gtk.gdk.color_parse(self.active_color)
185
(red2, green2, blue2) = (color.red, color.green, color.blue)
186
red = red1 + int(self.fade_level * abs(red1 - red2))
187
green = green1 + int(self.fade_level * abs(green1 - green2))
188
blue = blue1 + int(self.fade_level * abs(blue1 - blue2))
189
self.modify_fg(gtk.STATE_NORMAL, gtk.gdk.Color(red, green, blue))
190
self.fade_level -= 1.0 / (self.fade_duration / 25)
191
if self.fade_level > 0:
198
""" The PyRoom class"""
203
# Some Autosave Relative Variable
204
# autosave_disabled=False
207
#autosave_time=0 ## Minute before an autosave event
208
#tempfolder='/var/tmp/pyroom/'
210
def __init__(self, verbose, style, autosave_time, tempfolder, debug):
214
self.autosave_time=autosave_time
215
self.tempfolder = tempfolder
219
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
220
self.window.set_name('PyRoom')
221
self.window.set_title("PyRoom")
223
#self.window.fullscreen() #needles
224
self.window.connect('delete_event', self.delete_event)
225
self.window.connect('destroy', self.destroy)
227
self.textbox = gtksourceview.SourceView()
229
self.textbox.connect('scroll-event', self.scroll_event)
230
self.textbox.connect('key-press-event', self.key_press_event)
231
self.textbox.set_wrap_mode(gtk.WRAP_WORD)
233
self.fixed = gtk.Fixed()
234
self.vbox = gtk.VBox()
235
self.window.add(self.fixed)
236
self.fixed.put(self.vbox, 0, 0)
238
self.boxout = gtk.EventBox()
239
self.boxout.set_border_width(1)
240
self.boxin = gtk.EventBox()
241
self.boxin.set_border_width(1)
242
self.vbox.pack_start(self.boxout, True, True, 6)
243
self.boxout.add(self.boxin)
245
self.scrolled = gtk.ScrolledWindow()
246
self.boxin.add(self.scrolled)
247
self.scrolled.add(self.textbox)
248
self.scrolled.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
250
self.scrolled.set_property('resize-mode', gtk.RESIZE_PARENT)
251
self.textbox.set_property('resize-mode', gtk.RESIZE_PARENT)
252
self.vbox.set_property('resize-mode', gtk.RESIZE_PARENT)
257
self.status = FadeLabel()
258
self.hbox = gtk.HBox()
259
self.hbox.set_spacing(12)
260
self.hbox.pack_end(self.status, True, True, 0)
261
self.vbox.pack_end(self.hbox, False, False, 0)
262
self.status.set_alignment(0.0, 0.5)
263
self.status.set_justify(gtk.JUSTIFY_LEFT)
265
self.status.set_text(_('Welcome to PyRoom 1.0, type Control-H for help'))
266
self.window.show_all()
267
self.window.fullscreen() ## This seems ok with compiz !!! (AdamRooke)
268
#self.status.set_text(_('Welcome to PyRoom 1.0, type Control-H for help'))
271
# The Timer (for Autosave)
272
self.timeout_id=gobject.timeout_add(1000,self.timeout)
274
def delete_event(self, widget, event, data=None):
278
def destroy(self, widget, data=None):
282
def key_press_event(self, widget, event):
283
""" key press event dispatcher """
286
gtk.keysyms.Page_Up: self.prev_buffer,
287
gtk.keysyms.Page_Down: self.next_buffer,
288
gtk.keysyms.h: self.show_help,
289
gtk.keysyms.H: self.show_help,
290
gtk.keysyms.i: self.show_info,
291
gtk.keysyms.I: self.show_info,
292
gtk.keysyms.l: self.toggle_lines,
293
gtk.keysyms.L: self.toggle_lines,
294
gtk.keysyms.n: self.new_buffer,
295
gtk.keysyms.N: self.new_buffer,
296
gtk.keysyms.o: self.open_file,
297
gtk.keysyms.O: self.open_file,
298
gtk.keysyms.q: self.quit,
299
gtk.keysyms.Q: self.quit,
300
gtk.keysyms.s: self.save_file,
301
gtk.keysyms.S: self.save_file,
302
gtk.keysyms.w: self.close_buffer,
303
gtk.keysyms.W: self.close_buffer,
304
gtk.keysyms.y: self.redo,
305
gtk.keysyms.Y: self.redo,
306
gtk.keysyms.z: self.undo,
307
gtk.keysyms.Z: self.undo,
308
gtk.keysyms.plus: self.plus,
309
gtk.keysyms.equal: self.plus,
310
gtk.keysyms.minus: self.minus,
312
if event.state & gtk.gdk.CONTROL_MASK:
314
# Special case for Control-Shift-s
316
if event.state & gtk.gdk.SHIFT_MASK:
318
if event.state & gtk.gdk.SHIFT_MASK and event.keyval\
322
if bindings.has_key(event.keyval):
323
bindings[event.keyval]()
327
def scroll_event(self, widget, event):
328
""" Scroll event dispatcher """
330
if event.direction == gtk.gdk.SCROLL_UP:
332
elif event.direction == gtk.gdk.SCROLL_DOWN:
336
""" Create a new buffer and inserts help """
338
buffer = self.new_buffer()
339
buffer.begin_not_undoable_action()
340
buffer.set_text(HELP)
341
buffer.end_not_undoable_action()
343
def new_buffer(self):
344
""" Create a new buffer """
346
buffer = gtksourceview.SourceBuffer()
347
buffer.set_check_brackets(False)
348
buffer.set_highlight(False)
349
buffer.filename = FILE_UNNAMED
350
buffer.tmp_filename = None #CM
351
self.buffers.insert(self.current + 1, buffer)
352
buffer.place_cursor(buffer.get_start_iter())
356
def close_buffer(self):
357
""" Close current buffer """
359
if len(self.buffers) > 1:
360
self.buffers.pop(self.current)
361
self.current = min(len(self.buffers) - 1, self.current)
362
self.set_buffer(self.current)
366
def set_buffer(self, index):
367
""" Set current buffer """
369
if index >= 0 and index < len(self.buffers):
371
buffer = self.buffers[index]
372
self.textbox.set_buffer(buffer)
373
if hasattr(self, 'status'):
374
self.status.set_text(
375
_('Switching to buffer %(buffer_id)d (%(buffer_name)s)'
376
% {'buffer_id': self.current + 1, 'buffer_name'
379
def next_buffer(self):
380
""" Switch to next buffer """
382
if self.current < len(self.buffers) - 1:
386
self.set_buffer(self.current)
388
def prev_buffer(self):
389
""" Switch to prev buffer """
394
self.current = len(self.buffers) - 1
395
self.set_buffer(self.current)
397
def apply_style(self, style=None):
402
self.window.modify_bg(gtk.STATE_NORMAL,
403
gtk.gdk.color_parse(self.style['background'
405
self.textbox.modify_bg(gtk.STATE_NORMAL,
406
gtk.gdk.color_parse(self.style['background'
408
self.textbox.modify_base(gtk.STATE_NORMAL,
409
gtk.gdk.color_parse(self.style['background'
411
self.textbox.modify_text(gtk.STATE_NORMAL,
412
gtk.gdk.color_parse(self.style['foreground'
414
self.textbox.modify_fg(gtk.STATE_NORMAL,
415
gtk.gdk.color_parse(self.style['lines']))
416
self.status.active_color = self.style['foreground']
417
self.status.inactive_color = self.style['background']
418
self.boxout.modify_bg(gtk.STATE_NORMAL,
419
gtk.gdk.color_parse(self.style['border']))
420
font_and_size = '%s %d' % (self.style['font'],
421
self.style['fontsize'])
422
self.textbox.modify_font(pango.FontDescription(font_and_size))
424
gtk.rc_parse_string("""
425
style "pyroom-colored-cursor" {
426
GtkTextView::cursor-color = '"""
427
+ self.style['foreground']
430
class "GtkWidget" style "pyroom-colored-cursor"
432
(w, h) = (gtk.gdk.screen_width(), gtk.gdk.screen_height())
433
width = int(self.style['size'][0] * w)
434
height = int(self.style['size'][1] * h)
435
self.vbox.set_size_request(width, height)
436
self.fixed.move(self.vbox, int(((1 - self.style['size'][0]) * w)/ 2),
437
int(((1 - self.style['size'][1]) * h) / 2))
438
self.textbox.set_border_width(self.style['padding'])
440
def word_count(self, buffer):
441
""" Word count in a text buffer """
443
iter1 = buffer.get_start_iter()
445
iter2.forward_word_end()
447
while iter2.get_offset() != iter1.get_offset():
450
iter2.forward_word_end()
456
gobject.source_remove(self.timeout_id)
461
""" Display buffer information on status label for 5 seconds """
463
buffer = self.buffers[self.current]
464
if buffer.can_undo() or buffer.can_redo():
465
status = _(' (modified)')
468
self.status.set_text(_('Buffer %(buffer_id)d: %(buffer_name)s%(status)s, %(char_count)d byte(s), %(word_count)d word(s), %(lines)d line(s)') % {
469
'buffer_id': self.current + 1,
470
'buffer_name': buffer.filename,
472
'char_count': buffer.get_char_count(),
473
'word_count': self.word_count(buffer),
474
'lines': buffer.get_line_count(),
477
def scroll_down(self):
478
""" Scroll window down """
480
adj = self.scrolled.get_vadjustment()
481
if adj.upper > adj.page_size:
482
adj.value = min(adj.upper - adj.page_size, adj.value
483
+ adj.step_increment)
486
""" Scroll window up """
488
adj = self.scrolled.get_vadjustment()
489
if adj.value > adj.step_increment:
490
adj.value -= adj.step_increment
495
""" Undo last typing """
497
buffer = self.textbox.get_buffer()
498
if buffer.can_undo():
501
self.status.set_text(_('No more undo!'))
504
""" Redo last typing """
506
buffer = self.textbox.get_buffer()
507
if buffer.can_redo():
510
self.status.set_text(_('No more redo!'))
512
def toggle_lines(self):
513
""" Toggle lines number """
515
b = not self.textbox.get_show_line_numbers()
516
self.textbox.set_show_line_numbers(b)
521
chooser = gtk.FileChooserDialog('PyRoom', self.window,
522
gtk.FILE_CHOOSER_ACTION_OPEN,
523
buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
524
gtk.STOCK_OPEN, gtk.RESPONSE_OK))
525
chooser.set_default_response(gtk.RESPONSE_OK)
527
self.window.unfullscreen() # CM
529
self.window.fullscreen() # CM
530
if res == gtk.RESPONSE_OK:
531
buffer = self.new_buffer()
532
buffer.filename = chooser.get_filename()
534
#f = open(buffer.filename, 'r')
535
buffer = self.buffers[self.current]
536
buffer.begin_not_undoable_action()
537
#utf8 = unicode(f.read(), 'utf-8')
538
#buffer.set_text(utf8)
539
buffer.set_text(pyroom_io.open_file(buffer.filename))
540
buffer.end_not_undoable_action()
542
self.status.set_text(_('File %s open')
544
except IOError, (errno, strerror):
545
errortext = '''Unable to open %(filename)s.''' % {'filename': buffer.filename}
547
errortext += ' The file does not exist.'
549
errortext += ' You do not have permission to open the file.'
550
buffer.set_text(_(errortext))
552
print ('''Unable to open %(filename)s. %(traceback)s'''
553
% {'filename': buffer.filename, 'traceback': traceback.format_exc()})
554
self.status.set_text(_('Failed to open %s')
556
buffer.filename = FILE_UNNAMED
558
buffer.set_text(_('Unable to open %s\n'
561
print ('''Unable to open %(filename)s. %(traceback)s'''
562
% {'filename': buffer.filename,
563
'traceback': traceback.format_exc()})
564
buffer.filename = FILE_UNNAMED
566
self.status.set_text(_('Closed, no files selected'))
569
def save_file(self,buffer_id=None):
571
### buffer_id permit to save another buffer not only the current one (#CM)
573
buffer = self.buffers[self.current]
575
buffer = self.buffers[buffer_id]
577
if buffer.filename != FILE_UNNAMED:
578
#f = open(buffer.filename, 'w')
579
#txt = buffer.get_text(buffer.get_start_iter(),
580
# buffer.get_end_iter())
583
pyroom_io.save_file(buffer.filename, buffer.get_text(buffer.get_start_iter(),buffer.get_end_iter()))
584
buffer.begin_not_undoable_action()
585
buffer.end_not_undoable_action()
586
self.status.set_text(_('File %s saved') % buffer.filename)
592
def save_file_as(self):
595
buffer = self.buffers[self.current]
596
chooser = gtk.FileChooserDialog('PyRoom', self.window,
597
gtk.FILE_CHOOSER_ACTION_SAVE,
598
buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
599
gtk.STOCK_SAVE, gtk.RESPONSE_OK))
600
chooser.set_default_response(gtk.RESPONSE_OK)
601
if buffer.filename != FILE_UNNAMED:
602
chooser.set_filename(buffer.filename)
603
self.window.unfullscreen() # CM
605
self.window.fullscreen() #CM
606
if res == gtk.RESPONSE_OK:
607
buffer.filename = chooser.get_filename()
610
self.status.set_text(_('Closed, no files selected'))
616
""" Increases the font size"""
618
self.style['fontsize'] += 2
620
self.status.set_text(_('Font size increased'))
623
""" Decreases the font size"""
625
self.style['fontsize'] -= 2
627
self.status.set_text(_('Font size decreased'))
631
def autosave_file(self, buffer_id):
632
"""AutoSave the Buffer to temp folder"""
634
buffer=self.buffers[buffer_id]
636
# check if the path exist
637
if not os.path.exists(self.tempfolder):
638
os.mkdir(self.tempfolde)
640
if buffer.tmp_filename==None:
641
if buffer.filename==FILE_UNNAMED:
642
buffer.tmp_filename=tempfile.mkstemp(suffix="",prefix="noname_"+"tmp_",dir=self.tempfolder,text=True)[1]
643
#elif buffer.filename
645
buff_path,buff_name=os.path.split(buffer.filename)
646
print buff_path, buff_name
647
buffer.tmp_filename=tempfile.mkstemp(suffix="",prefix=buff_name+"_tmp_",dir=self.tempfolder,text=True)[1]
649
## some good old code :)) *Remove*
650
##if buffer.tmp_filename==None:
651
## buffer.tmp_filename=tempfile.mkstemp(suffix="",prefix="tmp",dir=self.tempfolder,text=True)[1]
653
#really saves the file
654
pyroom_io.save_file(buffer.tmp_filename, buffer.get_text(buffer.get_start_iter(),buffer.get_end_iter()))
656
#inform the user of the save operation
657
self.status.set_text(_('AutoSaving Buffer %d, to temp file %s') % (buffer_id, buffer.tmp_filename))
661
""" Autosave all buffer everey n minutes
662
to /var/tmp/pyroom_tmp[<Buffer_ID>]"""
663
##if self.autosave_disabled==False:
664
if int(self.autosave_time)!=0:
665
self.elapsed_sec=self.elapsed_sec + 1
667
print "running from %d seconds" % self.elapsed_sec #(debug)
668
if (self.elapsed_sec>=(int(self.autosave_time) * 60)):
669
for buffer in self.buffers:
670
self.autosave_file(self.buffers.index(buffer))
672
return True ## repeat timeout until true :))
674
self.status.set_text(("Warning!!! - Autosaving Feature disabled"))
675
if self.verbose==True:
676
print "Warning!!! Autosave Feature disabled"
41
from styles import styles
680
43
if __name__ == '__main__':
682
tempfolder='/var/tmp/pyroom/'
686
#the default minutes i must wait before autosave
689
49
# Get commandline args
691
args, files = getopt.getopt(sys.argv[1:],'vlCd', ['style=','autosave_time='])
51
args, files = getopt.getopt(sys.argv[1:],'vslC', ['style=','autosave_time='])
692
52
except getopt.GetoptError:
693
53
# Print help information
694
print "Usage: pyroom [-v] [-l] [-C] [-d] [--style={style name}] "
695
print " [--autosave_time={minutes}/{0 = Autosave Disabled} ]file1 file2"
54
print _("Usage: pyroom [-v] [-s] [-l] [-C] [--style={style name}] [--autosave_time={minutes}/{0 = Autosave Disabled}] file1 file2")
55
#print _("Usage: pyroom [-v] [-s] [-l] [-C] [--style={style name}] file1 file2")
58
set_autosave_time(3) ## if no autosave option is passed on command line set autosave every 3 minues
698
59
for arg, val in args:
702
### CM Print The Aviable Styles
703
print "Aviable Styles : "
709
print "Cleaning Pyroom Temp Folder : ",tempfolder
710
response=raw_input("proceed [Yes/No]?")
711
if string.lower(response)=="yes":
712
killlist = os.listdir(tempfolder)
713
if len(killlist)==0 : sys.exit(0)
714
for killfile in killlist:
715
print "removing File :", os.path.join(tempfolder,killfile)
716
os.remove(os.path.join(tempfolder,killfile))
718
print "Nothing deleted..."
724
if arg == '--autosave_time':
726
#elif autosave__time is _uninitialized: codice inutile e dannoso (remove)
63
print "Aviable Styles : "
68
elif arg == '--style':
75
elif arg == '--autosave_time':
76
set_autosave_time(int(val)) #set autosave timeout on user request
79
print "Autosave Time in Minutes : %d" % get_autosave_time() #(debug)
729
if debug==True: print "autosave_time =",autosave_time
731
84
# Create relevant buffers for file and load them
734
pyroom = PyRoom(verbose, styles[style], autosave_time, tempfolder, debug)
735
#pyroom.autosave_time=autosave_time ## set the autosave timeout
736
#pyroom.tempfolder=tempfolder
737
#print pyroom.autosave_time, autosave_time
85
pyroom = BasicEdit(styles[style],verbose, ret)
739
87
for filename in files:
740
88
buffer = pyroom.new_buffer()
741
89
buffer.filename = filename
742
90
if os.path.exists(filename):
745
#f = open(filename, 'r')
92
print "Automatically opened %s" %(filename)
93
f = open(filename, 'r')
746
94
buffer.begin_not_undoable_action()
747
#buffer.set_text(unicode(f.read(), 'utf-8'))
748
buffer.set_text(pyroom_io.open_file(filename))
95
buffer.set_text(unicode(f.read(), 'utf-8'))
749
96
buffer.end_not_undoable_action()
751
98
except IOError, (errno, strerror):
752
99
errortext = '''Unable to open %(filename)s.''' % {'filename': buffer.filename}
754
errortext += ' You do not have permission to open the file.'
101
errortext += _(' You do not have permission to open the file.')
755
102
buffer.set_text(_(errortext))
757
print ('''Unable to open %(filename)s. %(traceback)s'''
758
% {'filename': buffer.filename,
759
'traceback': traceback.format_exc()})
104
print (_('Unable to open %(filename)s. %(traceback)s'
105
% {'filename': buffer.filename,
106
'traceback': traceback.format_exc()})
760
108
buffer.filename = FILE_UNNAMED
762
110
buffer.set_text(_('Unable to open %s\n'
763
111
% buffer.filename))
765
print ('''Unable to open %(filename)s. %(traceback)s'''
766
% {'filename': buffer.filename,
767
'traceback': traceback.format_exc()})
113
print (_('Unable to open %(filename)s. %(traceback)s'
114
% {'filename': buffer.filename,
115
'traceback': traceback.format_exc()}))
768
116
buffer.filename = FILE_UNNAMED
770
118
pyroom.set_buffer(0)
771
119
pyroom.close_buffer()