~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.2.1/pjsip-apps/src/pygui/chatgui.py

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# $Id: chatgui.py 4757 2014-02-21 07:53:31Z nanang $
 
2
#
 
3
# pjsua Python GUI Demo
 
4
#
 
5
# Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
 
6
#
 
7
# This program is free software; you can redistribute it and/or modify
 
8
# it under the terms of the GNU General Public License as published by
 
9
# the Free Software Foundation; either version 2 of the License, or
 
10
# (at your option) any later version.
 
11
#
 
12
# This program is distributed in the hope that it will be useful,
 
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
# GNU General Public License for more details.
 
16
#
 
17
# You should have received a copy of the GNU General Public License
 
18
# along with this program; if not, write to the Free Software
 
19
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 
20
#
 
21
import sys
 
22
if sys.version_info[0] >= 3: # Python 3
 
23
        import tkinter as tk
 
24
        from tkinter import ttk
 
25
        from tkinter import messagebox as msgbox
 
26
else:
 
27
        import Tkinter as tk
 
28
        import ttk
 
29
        import tkMessageBox as msgbox
 
30
 
 
31
 
 
32
class TextObserver:
 
33
        def onSendMessage(self, msg):
 
34
                pass
 
35
        def onStartTyping(self):
 
36
                pass
 
37
        def onStopTyping(self):
 
38
                pass
 
39
                
 
40
class TextFrame(ttk.Frame):
 
41
        def __init__(self, master, observer):
 
42
                ttk.Frame.__init__(self, master)
 
43
                self._observer = observer
 
44
                self._isTyping = False
 
45
                self._createWidgets()
 
46
 
 
47
        def _onSendMessage(self, event):
 
48
                send_text = self._typingBox.get("1.0", tk.END).strip()
 
49
                if send_text == '':
 
50
                        return
 
51
                
 
52
                self.addMessage('me: ' + send_text)
 
53
                self._typingBox.delete("0.0", tk.END)
 
54
                self._onTyping(None)
 
55
                
 
56
                # notify app for sending message
 
57
                self._observer.onSendMessage(send_text)
 
58
                
 
59
        def _onTyping(self, event):
 
60
                # notify app for typing indication
 
61
                is_typing = self._typingBox.get("1.0", tk.END).strip() != ''
 
62
                if is_typing != self._isTyping:
 
63
                        self._isTyping = is_typing
 
64
                        if is_typing:
 
65
                                self._observer.onStartTyping()
 
66
                        else:
 
67
                                self._observer.onStopTyping()
 
68
                
 
69
        def _createWidgets(self):
 
70
                self.rowconfigure(0, weight=1)
 
71
                self.rowconfigure(1, weight=0)
 
72
                self.rowconfigure(2, weight=0)
 
73
                self.columnconfigure(0, weight=1)
 
74
                self.columnconfigure(1, weight=0)
 
75
                
 
76
                self._text = tk.Text(self, width=50, height=30, font=("Arial", "10"))
 
77
                self._text.grid(row=0, column=0, sticky='nswe')
 
78
                self._text.config(state=tk.DISABLED)
 
79
                self._text.tag_config("info", foreground="darkgray", font=("Arial", "9", "italic"))
 
80
                
 
81
                scrl = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self._text.yview)
 
82
                self._text.config(yscrollcommand=scrl.set)
 
83
                scrl.grid(row=0, column=1, sticky='nsw')
 
84
                
 
85
                self._typingBox = tk.Text(self, width=50, height=1, font=("Arial", "10"))
 
86
                self._typingBox.grid(row=1, columnspan=2, sticky='we', pady=0)
 
87
                
 
88
                self._statusBar = tk.Label(self, anchor='w', font=("Arial", "8", "italic"))
 
89
                self._statusBar.grid(row=2, columnspan=2, sticky='we')
 
90
                
 
91
                self._typingBox.bind('<Return>', self._onSendMessage)
 
92
                self._typingBox.bind("<Key>", self._onTyping)
 
93
                self._typingBox.focus_set()
 
94
                
 
95
        def addMessage(self, msg, is_chat = True):
 
96
                self._text.config(state=tk.NORMAL)
 
97
                if is_chat:
 
98
                        self._text.insert(tk.END, msg+'\r\n')
 
99
                else:
 
100
                        self._text.insert(tk.END, msg+'\r\n', 'info')
 
101
                self._text.config(state=tk.DISABLED)
 
102
                self._text.yview(tk.END)
 
103
 
 
104
        def setTypingIndication(self, who, is_typing):
 
105
                if is_typing:
 
106
                        self._statusBar['text'] = "'%s' is typing.." % (who)
 
107
                else:
 
108
                        self._statusBar['text'] = ''
 
109
 
 
110
class AudioState:
 
111
        NULL, INITIALIZING, CONNECTED, DISCONNECTED, FAILED = range(5)
 
112
                        
 
113
class AudioObserver:
 
114
        def onHangup(self, peer_uri):
 
115
                pass
 
116
        def onHold(self, peer_uri):
 
117
                pass
 
118
        def onUnhold(self, peer_uri):
 
119
                pass
 
120
        def onRxMute(self, peer_uri, is_muted):
 
121
                pass
 
122
        def onRxVol(self, peer_uri, vol_pct):
 
123
                pass
 
124
        def onTxMute(self, peer_uri, is_muted):
 
125
                pass
 
126
                        
 
127
 
 
128
class AudioFrame(ttk.Labelframe):
 
129
        def __init__(self, master, peer_uri, observer):
 
130
                ttk.Labelframe.__init__(self, master, text=peer_uri)
 
131
                self.peerUri = peer_uri
 
132
                self._observer = observer
 
133
                self._initFrame = None
 
134
                self._callFrame = None
 
135
                self._rxMute = False
 
136
                self._txMute = False
 
137
                self._state = AudioState.NULL
 
138
                
 
139
                self._createInitWidgets()
 
140
                self._createWidgets()
 
141
                
 
142
        def updateState(self, state):
 
143
                if self._state == state:
 
144
                        return
 
145
 
 
146
                if state == AudioState.INITIALIZING:
 
147
                        self._callFrame.pack_forget()
 
148
                        self._initFrame.pack(fill=tk.BOTH)
 
149
                        self._btnCancel.pack(side=tk.TOP)
 
150
                        self._lblInitState['text'] = 'Intializing..'
 
151
 
 
152
                elif state == AudioState.CONNECTED:
 
153
                        self._initFrame.pack_forget()
 
154
                        self._callFrame.pack(fill=tk.BOTH)                      
 
155
                else:
 
156
                        self._callFrame.pack_forget()
 
157
                        self._initFrame.pack(fill=tk.BOTH)
 
158
                        if state == AudioState.FAILED:
 
159
                                self._lblInitState['text'] = 'Failed'
 
160
                        else:
 
161
                                self._lblInitState['text'] = 'Normal cleared'
 
162
                                self._btnCancel.pack_forget()
 
163
                        
 
164
                        self._btnHold['text'] = 'Hold'
 
165
                        self._btnHold.config(state=tk.NORMAL)
 
166
                        self._rxMute = False
 
167
                        self._txMute = False
 
168
                        self.btnRxMute['text'] = 'Mute'
 
169
                        self.btnTxMute['text'] = 'Mute'
 
170
                        self.rxVol.set(5.0)
 
171
                
 
172
                # save last state
 
173
                self._state = state
 
174
                
 
175
        def setStatsText(self, stats_str):
 
176
                self.stat.config(state=tk.NORMAL)
 
177
                self.stat.delete("0.0", tk.END)
 
178
                self.stat.insert(tk.END, stats_str)
 
179
                self.stat.config(state=tk.DISABLED)
 
180
                
 
181
        def _onHold(self):
 
182
                self._btnHold.config(state=tk.DISABLED)
 
183
                # notify app
 
184
                if self._btnHold['text'] == 'Hold':
 
185
                        self._observer.onHold(self.peerUri)
 
186
                        self._btnHold['text'] = 'Unhold'
 
187
                else:
 
188
                        self._observer.onUnhold(self.peerUri)
 
189
                        self._btnHold['text'] = 'Hold'
 
190
                self._btnHold.config(state=tk.NORMAL)
 
191
 
 
192
        def _onHangup(self):
 
193
                # notify app
 
194
                self._observer.onHangup(self.peerUri)
 
195
 
 
196
        def _onRxMute(self):
 
197
                # notify app
 
198
                self._rxMute = not self._rxMute
 
199
                self._observer.onRxMute(self.peerUri, self._rxMute)
 
200
                self.btnRxMute['text'] = 'Unmute' if self._rxMute else 'Mute'
 
201
                
 
202
        def _onRxVol(self, event):
 
203
                # notify app
 
204
                vol = self.rxVol.get()
 
205
                self._observer.onRxVol(self.peerUri, vol*10.0)
 
206
 
 
207
        def _onTxMute(self):
 
208
                # notify app
 
209
                self._txMute = not self._txMute
 
210
                self._observer.onTxMute(self.peerUri, self._txMute)
 
211
                self.btnTxMute['text'] = 'Unmute' if self._txMute else 'Mute'
 
212
 
 
213
        def _createInitWidgets(self):
 
214
                self._initFrame = ttk.Frame(self)
 
215
                #self._initFrame.pack(fill=tk.BOTH)
 
216
 
 
217
        
 
218
                self._lblInitState = tk.Label(self._initFrame, font=("Arial", "12"), text='')
 
219
                self._lblInitState.pack(side=tk.TOP, fill=tk.X, expand=1)
 
220
                
 
221
                # Operation: cancel/kick
 
222
                self._btnCancel = ttk.Button(self._initFrame, text = 'Cancel', command=self._onHangup)
 
223
                self._btnCancel.pack(side=tk.TOP)
 
224
                                
 
225
        def _createWidgets(self):
 
226
                self._callFrame = ttk.Frame(self)
 
227
                #self._callFrame.pack(fill=tk.BOTH)
 
228
                
 
229
                # toolbar
 
230
                toolbar = ttk.Frame(self._callFrame)
 
231
                toolbar.pack(side=tk.TOP, fill=tk.X)
 
232
                self._btnHold = ttk.Button(toolbar, text='Hold', command=self._onHold)
 
233
                self._btnHold.pack(side=tk.LEFT, fill=tk.Y)
 
234
                #self._btnXfer = ttk.Button(toolbar, text='Transfer..')
 
235
                #self._btnXfer.pack(side=tk.LEFT, fill=tk.Y)
 
236
                self._btnHangUp = ttk.Button(toolbar, text='Hangup', command=self._onHangup)
 
237
                self._btnHangUp.pack(side=tk.LEFT, fill=tk.Y)
 
238
 
 
239
                # volume tool
 
240
                vol_frm = ttk.Frame(self._callFrame)
 
241
                vol_frm.pack(side=tk.TOP, fill=tk.X)
 
242
                
 
243
                self.rxVolFrm = ttk.Labelframe(vol_frm, text='RX volume')
 
244
                self.rxVolFrm.pack(side=tk.LEFT, fill=tk.Y)
 
245
                
 
246
                self.btnRxMute = ttk.Button(self.rxVolFrm, width=8, text='Mute', command=self._onRxMute)
 
247
                self.btnRxMute.pack(side=tk.LEFT)
 
248
                self.rxVol = tk.Scale(self.rxVolFrm, orient=tk.HORIZONTAL, from_=0.0, to=10.0, showvalue=1) #, tickinterval=10.0, showvalue=1)
 
249
                self.rxVol.set(5.0)
 
250
                self.rxVol.bind("<ButtonRelease-1>", self._onRxVol)
 
251
                self.rxVol.pack(side=tk.LEFT)
 
252
                
 
253
                self.txVolFrm = ttk.Labelframe(vol_frm, text='TX volume')
 
254
                self.txVolFrm.pack(side=tk.RIGHT, fill=tk.Y)
 
255
                
 
256
                self.btnTxMute = ttk.Button(self.txVolFrm, width=8, text='Mute', command=self._onTxMute)
 
257
                self.btnTxMute.pack(side=tk.LEFT)
 
258
                
 
259
                # stat
 
260
                self.stat = tk.Text(self._callFrame, width=10, height=2, bg='lightgray', relief=tk.FLAT, font=("Courier", "9"))
 
261
                self.stat.insert(tk.END, 'stat here')
 
262
                self.stat.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1)
 
263
 
 
264
 
 
265
class ChatObserver(TextObserver, AudioObserver):
 
266
        def onAddParticipant(self):
 
267
                pass
 
268
        def onStartAudio(self):
 
269
                pass
 
270
        def onStopAudio(self):
 
271
                pass
 
272
        def onCloseWindow(self):
 
273
                pass
 
274
                
 
275
class ChatFrame(tk.Toplevel):
 
276
        """
 
277
        Room
 
278
        """
 
279
        def __init__(self, observer):
 
280
                tk.Toplevel.__init__(self)
 
281
                self.protocol("WM_DELETE_WINDOW", self._onClose)
 
282
                self._observer = observer
 
283
 
 
284
                self._text = None
 
285
                self._text_shown = True
 
286
                
 
287
                self._audioEnabled = False
 
288
                self._audioFrames = []
 
289
                self._createWidgets()
 
290
        
 
291
        def _createWidgets(self):
 
292
                # toolbar
 
293
                self.toolbar = ttk.Frame(self)
 
294
                self.toolbar.pack(side=tk.TOP, fill=tk.BOTH)
 
295
                
 
296
                btnText = ttk.Button(self.toolbar, text='Show/hide text', command=self._onShowHideText)
 
297
                btnText.pack(side=tk.LEFT, fill=tk.Y)
 
298
                btnAudio = ttk.Button(self.toolbar, text='Start/stop audio', command=self._onStartStopAudio)
 
299
                btnAudio.pack(side=tk.LEFT, fill=tk.Y)
 
300
                
 
301
                ttk.Separator(self.toolbar, orient=tk.VERTICAL).pack(side=tk.LEFT, fill=tk.Y, padx = 4)
 
302
 
 
303
                btnAdd = ttk.Button(self.toolbar, text='Add participant..', command=self._onAddParticipant)
 
304
                btnAdd.pack(side=tk.LEFT, fill=tk.Y)
 
305
 
 
306
                # media frame
 
307
                self.media = ttk.Frame(self)
 
308
                self.media.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1)
 
309
                
 
310
                # create Text Chat frame
 
311
                self.media_left = ttk.Frame(self.media)
 
312
                self._text = TextFrame(self.media_left, self._observer)
 
313
                self._text.pack(fill=tk.BOTH, expand=1)
 
314
                self.media_left.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
 
315
                
 
316
                # create other media frame
 
317
                self.media_right = ttk.Frame(self.media)
 
318
                
 
319
        def _arrangeMediaFrames(self):
 
320
                if len(self._audioFrames) == 0:
 
321
                        self.media_right.pack_forget()
 
322
                        return
 
323
                
 
324
                self.media_right.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
 
325
                MAX_ROWS = 3
 
326
                row_num = 0
 
327
                col_num = 1
 
328
                for frm in self._audioFrames:
 
329
                        frm.grid(row=row_num, column=col_num, sticky='nsew', padx=5, pady=5)
 
330
                        row_num += 1
 
331
                        if row_num >= MAX_ROWS:
 
332
                                row_num  = 0
 
333
                                col_num += 1
 
334
        
 
335
        def _onShowHideText(self):
 
336
                self.textShowHide(not self._text_shown)
 
337
                
 
338
        def _onAddParticipant(self):
 
339
                self._observer.onAddParticipant()
 
340
        
 
341
        def _onStartStopAudio(self):
 
342
                self._audioEnabled = not self._audioEnabled
 
343
                if self._audioEnabled:
 
344
                        self._observer.onStartAudio()
 
345
                else:
 
346
                        self._observer.onStopAudio()
 
347
                self.enableAudio(self._audioEnabled)
 
348
                
 
349
        def _onClose(self):
 
350
                self._observer.onCloseWindow()
 
351
                        
 
352
        # APIs
 
353
        
 
354
        def bringToFront(self):
 
355
                self.deiconify()
 
356
                self.lift()
 
357
                self._text._typingBox.focus_set()
 
358
                
 
359
        def textAddMessage(self, msg, is_chat = True):
 
360
                self._text.addMessage(msg, is_chat)
 
361
                
 
362
        def textSetTypingIndication(self, who, is_typing = True):
 
363
                self._text.setTypingIndication(who, is_typing)
 
364
                
 
365
        def addParticipant(self, participant_uri):
 
366
                aud_frm = AudioFrame(self.media_right, participant_uri, self._observer)
 
367
                self._audioFrames.append(aud_frm)
 
368
        
 
369
        def delParticipant(self, participant_uri):
 
370
                for aud_frm in self._audioFrames:
 
371
                        if participant_uri == aud_frm.peerUri:
 
372
                                self._audioFrames.remove(aud_frm)
 
373
                                # need to delete aud_frm manually?
 
374
                                aud_frm.destroy()
 
375
                                return
 
376
 
 
377
        def textShowHide(self, show = True):
 
378
                if show:
 
379
                        self.media_left.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
 
380
                        self._text._typingBox.focus_set()
 
381
                else:
 
382
                        self.media_left.pack_forget()
 
383
                self._text_shown = show
 
384
        
 
385
        def enableAudio(self, is_enabled = True):
 
386
                if is_enabled:
 
387
                        self._arrangeMediaFrames()
 
388
                else:
 
389
                        self.media_right.pack_forget()
 
390
                self._audioEnabled = is_enabled
 
391
                        
 
392
        def audioUpdateState(self, participant_uri, state):
 
393
                for aud_frm in self._audioFrames:
 
394
                        if participant_uri == aud_frm.peerUri:
 
395
                                aud_frm.updateState(state)
 
396
                                break
 
397
                if state >= AudioState.DISCONNECTED and len(self._audioFrames) == 1:
 
398
                        self.enableAudio(False)
 
399
                else:
 
400
                        self.enableAudio(True)
 
401
                        
 
402
        def audioSetStatsText(self, participant_uri, stats_str):
 
403
                for aud_frm in self._audioFrames:
 
404
                        if participant_uri == aud_frm.peerUri:
 
405
                                aud_frm.setStatsText(stats_str)
 
406
                                break
 
407
                                
 
408
if __name__ == '__main__':
 
409
        root = tk.Tk()
 
410
        root.title("Chat")
 
411
        root.columnconfigure(0, weight=1)
 
412
        root.rowconfigure(0, weight=1)
 
413
        
 
414
        obs = ChatObserver()
 
415
        dlg = ChatFrame(obs)
 
416
        #dlg = TextFrame(root)
 
417
        #dlg = AudioFrame(root)
 
418
 
 
419
        #dlg.pack(fill=tk.BOTH, expand=1)
 
420
        root.mainloop()