aboutsummaryrefslogtreecommitdiff
blob: cec88889a1634ef4097754ee6654d60f7dabd5c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/usr/bin/env python
#
#      VirtualTerminal.py
#
#      Copyright 2007 Edward Andrew Robinson <earobinson@gmail>
#
#      This program is free software; you can redistribute it and/or modify
#      it under the terms of the GNU General Public License as published by
#      the Free Software Foundation; either version 2 of the License, or
#      (at your option) any later version.
#
#      This program is distributed in the hope that it will be useful,
#      but WITHOUT ANY WARRANTY; without even the implied warranty of
#      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#      GNU General Public License for more details.
#
#      You should have received a copy of the GNU General Public License
#      along with this program; if not, write to the Free Software
#      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#

# Imports
import os
import vte
import gtk
import time

class VirtualTerminal(vte.Terminal):
    def __init__(self, log_file = None, history_length = 5, prompt_watch = {}, prompt_auto_reply = True, icon = None):
        # Set up terminal
        vte.Terminal.__init__(self)

        self.history = []
        self.history_length = history_length
        self.icon = icon
        self.last_row_logged = 0
        self.log_file = log_file
        self.prompt_auto_reply = prompt_auto_reply
        self.prompt_watch = prompt_watch

        self.connect('eof', self.run_command_done_callback)
        self.connect('child-exited', self.run_command_done_callback)
        self.connect('cursor-moved', self.contents_changed_callback)

        if False:
            self.connect('char-size-changed', self.activate_action, 'char-size-changed')
            #self.connect('child-exited', self.activate_action, 'child-exited')
            self.connect('commit', self.activate_action, 'commit')
            self.connect('contents-changed', self.activate_action, 'contents-changed')
            #self.connect('cursor-moved', self.activate_action, 'cursor-moved')
            self.connect('decrease-font-size', self.activate_action, 'decrease-font-size')
            self.connect('deiconify-window', self.activate_action, 'deiconify-window')
            self.connect('emulation-changed', self.activate_action, 'emulation-changed')
            self.connect('encoding-changed', self.activate_action, 'encoding-changed')
            #self.connect('eof', self.activate_action, 'eof')
            self.connect('icon-title-changed', self.activate_action, 'icon-title-changed')
            self.connect('iconify-window', self.activate_action, 'iconify-window')
            self.connect('increase-font-size', self.activate_action, 'increase-font-size')
            self.connect('lower-window', self.activate_action, 'lower-window')
            self.connect('maximize-window', self.activate_action, 'maximize-window')
            self.connect('move-window', self.activate_action, 'move-window')
            self.connect('raise-window', self.activate_action, 'raise-window')
            self.connect('refresh-window', self.activate_action, 'refresh-window')
            self.connect('resize-window', self.activate_action, 'resize-window')
            self.connect('restore-window', self.activate_action, 'restore-window')
            self.connect('selection-changed', self.activate_action, 'selection-changed')
            self.connect('status-line-changed', self.activate_action, 'status-line-changed')
            self.connect('text-deleted', self.activate_action, 'text-deleted')
            self.connect('text-inserted', self.activate_action, 'text-inserted')
            self.connect('text-modified', self.activate_action, 'text-modified')
            self.connect('text-scrolled', self.activate_action, 'text-scrolled')
            self.connect('window-title-changed', self.activate_action, 'window-title-changed')

    def activate_action(self, action, string):
        print 'Action ' + action.get_name() + ' activated ' + str(string)

    def capture_text(self,text,text2,text3,text4):
        return True

    def contents_changed_callback(self, terminal):
        '''Gets the last line printed to the terminal, it will log
        this line using self.log() (if the logger is on, and it will
        also prompt this line using self.prompt() if the line needs
        prompting'''
        column,row = self.get_cursor_position()
        if self.last_row_logged != row:
            off = row-self.last_row_logged
            text = self.get_text_range(row-off,0,row-1,-1,self.capture_text)
            self.last_row_logged=row
            text = text.strip()

            # Log
            self.log(text)

            # Prompter
            self.prompter()

    def get_last_line(self):
        terminal_text = self.get_text(self.capture_text)
        terminal_text = terminal_text.split('\\\\n')
        ii = len(terminal_text) - 1
        while terminal_text[ii] == '':
            ii = ii - 1
        terminal_text = terminal_text[ii]

        return terminal_text

    def log(self, text):
        '''if self.log_file is not None the the line will be logged to
        self.log_file. This function also stors the info in self.histoy
        if self.history_lenght > 0'''
        if self.log_file != None:
            date_string = time.strftime('[%d %b %Y %H:%M:%S] ', time.localtime())
            file = open(self.log_file, 'a')
            file.write(date_string + text + '\\\\n')
            file.close

        # Append to internal history
        if self.history_length != 0:
            if len(self.history) >= self.history_length:
                self.history.pop(0)
            self.history.append(text)

    def prompter(self):
        last_line = self.get_last_line()
        if last_line in self.prompt_watch:
            if self.prompt_auto_reply == False:
                message = ''
                for ii in self.prompt_watch[last_line]:
                    message = message + self.history[self.history_length - 1 - ii]
                if self.yes_no_question(message):
                    self.feed_child('Yes\\\\n')
                    # TODO not sure why this is needed twice
                    self.feed_child('Yes\\\\n')
                else:
                    self.feed_child('No\\\\n')
            else:
                self.feed_child('Yes\\\\n')

    def run_command(self, command_string):
        '''run_command runs the command_string in the terminal. This
        function will only return when self.thred_running is set to
        True, this is done by run_command_done_callback'''
        self.thread_running = True
        spaces = ''
        for ii in range(80 - len(command_string) - 2):
            spaces = spaces + ' '
        self.feed('$ ' + str(command_string) + spaces)
        self.log('$ ' + str(command_string) + spaces)

        command = command_string.split(' ')
        pid =  self.fork_command(command=command[0], argv=command, directory=os.getcwd())

        while self.thread_running:
            #time.sleep(.01)
            gtk.main_iteration()

    def run_command_done_callback(self, terminal):
        '''When called this function sets the thread as done allowing
        the run_command function to exit'''
        #print 'child done'
        self.thread_running = False

    def yes_no_question(self, message):
        message = message.replace('\\\\n\\\\n', '[NEWLINE][NEWLINE]').replace('\\\\n', '').replace('[NEWLINE]', '\\\\n')

        if message.find('?') == -1:
            message = message + '\\\\n\\\\nDo you want to continue?'

        type=gtk.MESSAGE_QUESTION
        if message.lower().find('warning') != -1:
            type=gtk.MESSAGE_WARNING

        dialog = gtk.MessageDialog(parent=None, flags=0, type=type, buttons=gtk.BUTTONS_YES_NO, message_format=message)
        dialog.set_icon(self.icon)
        dialog.show_all()
        responce = dialog.run()
        dialog.destroy()

        # Responce == yes
        return responce == -8