5 # Copyright 2004-2005, under the GPL
10 from twisted
.internet
import gtk2reactor
12 from twisted
.internet
import reactor
, protocol
13 import twisted
.internet
.error
19 #standard python2.2 libraries
27 import xml
.dom
.minidom
31 def get_header_size(filename
):
33 file = open(filename
, 'r')
39 return size
+ 4 #include the size chunk after "data"
44 def append_empty_data(self
, filename
, size
):
45 file = open(filename
, 'a')
50 def get_sound_list(snapshot
):
51 doc
= xml
.dom
.minidom
.parse(snapshot
)
54 playlists_tag
= doc
.getElementsByTagName('Playlists')
55 playlists
= playlists_tag
[0].getElementsByTagName('Playlist')
56 for play
in playlists
:
57 regions
= play
.getElementsByTagName('Region')
58 for region
in regions
:
59 regionlist
.append(region
.getAttribute('source-0'))
60 regionlist
.append(region
.getAttribute('source-1'))
61 regionlist
.append(region
.getAttribute('source-2'))
62 regionlist
.append(region
.getAttribute('source-3'))
63 regionlist
.append(region
.getAttribute('source-4'))
64 regionlist
.append(region
.getAttribute('source-5'))
67 sources
= doc
.getElementsByTagName('Source')
68 for source
in sources
:
69 sourcelist
[source
.getAttribute('id')] = str(source
.getAttribute('name'))
73 if sourcelist
.has_key(id):
74 soundlist
.append(sourcelist
[id])
78 def raise_error(string
, parent
):
79 dialog
= gtk
.MessageDialog(parent
, gtk
.DIALOG_MODAL | gtk
.DIALOG_DESTROY_WITH_PARENT
,
80 gtk
.MESSAGE_WARNING
, gtk
.BUTTONS_OK
, string
)
86 def delete_snap(self
, session
, collab
, snap
):
87 sessions
= self
._data
['sessions']
88 sessions
[session
]['collabs'][collab
]['snaps'].remove(snap
)
89 self
._data
['sessions'] = sessions
91 def delete_collab(self
,session
, collab
):
92 sessions
= self
._data
['sessions']
93 del sessions
[session
]['collabs'][collab
]
94 self
._data
['sessions'] = sessions
96 def delete_session(self
, session
):
97 sessions
= self
._data
['sessions']
99 self
._data
['sessions'] = sessions
101 def add_snap(self
, session_name
, collab_name
, snap_name
):
102 sessions
= self
._data
['sessions']
103 sessions
[session_name
]['collabs'][collab_name
]['snaps'].append(snap_name
)
104 sessions
[session_name
]['collabs'][collab_name
]['snaps'].sort()
105 self
._data
['sessions'] = sessions
107 g_display
.update_snap_view()
109 def add_collab(self
, session_name
, collab_name
, ip_address
, port
):
110 sessions
= self
._data
['sessions']
111 sessions
[session_name
]['collabs'][collab_name
] = {}
112 sessions
[session_name
]['collabs'][collab_name
]['snaps'] = []
113 sessions
[session_name
]['collabs'][collab_name
]['sounds'] = []
114 sessions
[session_name
]['collabs'][collab_name
]['ip'] = ip_address
115 sessions
[session_name
]['collabs'][collab_name
]['port'] = port
116 sessions
[session_name
]['collabs'][collab_name
]['v2paths'] = True
117 self
._data
['sessions'] = sessions
119 client
= ExchangeClientFactory(session_name
, collab_name
, None, self
.debug_mode
)
120 reactor
.connectTCP(ip_address
, port
, client
)
121 g_display
.show_status("connecting")
123 g_display
.update_collab_view()
125 def add_session(self
, session_path
):
126 sessions
= self
._data
['sessions']
128 session_name
= session_path
[session_path
.rfind('/', 0, len(session_path
)-2)+1: -1]
129 sessions
[session_name
] = {}
130 sessions
[session_name
]['path'] = session_path
131 sessions
[session_name
]['collabs'] = {}
132 sessions
[session_name
]['collabs'][self
._data
['user']] = {}
133 sessions
[session_name
]['collabs'][self
._data
['user']]['snaps'] = []
134 sessions
[session_name
]['collabs'][self
._data
['user']]['sounds'] = []
135 if os
.path
.isdir (os
.path
.join (session_path
,'sounds')):
136 sessions
[session_name
]['collabs'][self
._data
['user']]['v2paths'] = False
139 sessions
[session_name
]['collabs'][self
._data
['user']]['v2paths'] = True
141 self
._data
['sessions'] = sessions
143 self
.rescan_session(session_name
)
145 def rescan_session(self
, session_name
):
146 sessions
= self
._data
['sessions']
148 session_path
= sessions
[session_name
]['path']
149 sessions
[session_name
]['collabs'][self
._data
['user']]['snaps'] = self
._scan
_snapshots
(session_path
)
150 sessions
[session_name
]['collabs'][self
._data
['user']]['sounds'] = self
._scan
_sounds
(session_name
)
152 self
._data
['sessions'] = sessions
154 g_display
.update_snap_view()
156 print self
._data
['sessions']
158 def create_session(self
, session_path
):
159 sessions
= self
._data
['sessions']
161 session_name
= session_path
[session_path
.rfind('/', 0, len(session_path
)-2)+1: ]
163 os
.mkdir(session_path
)
164 os
.mkdir(os
.path
.join (session_path
,'interchange'))
165 os
.mkdir(os
.path
.join (session_path
,'interchange',session_name
))
166 os
.mkdir(os
.path
.join (session_path
,'interchange',session_name
,'audiofiles'))
168 raise_error("Could not create session directory", g_display
.window
)
171 sessions
[session_name
] = {}
172 sessions
[session_name
]['path'] = session_path
173 sessions
[session_name
]['collabs'] = {}
174 sessions
[session_name
]['collabs'][self
._data
['user']] = {}
175 sessions
[session_name
]['collabs'][self
._data
['user']]['snaps'] = []
176 sessions
[session_name
]['collabs'][self
._data
['user']]['sounds'] = []
178 self
._data
['sessions'] = sessions
179 print self
._data
['sessions']
181 def get_session_path(self
, session
):
182 sessions
= self
._data
['sessions']
183 return sessions
[session
]['path']
186 return self
._data
['user']
188 def set_user(self
, username
):
189 self
._data
['user'] = username
191 def get_collab_ip(self
, session
, collab
):
192 sessions
= self
._data
['sessions']
193 return sessions
[session
]['collabs'][collab
]['ip']
198 def get_sessions(self
):
199 sessions
= self
._data
['sessions']
200 sess
= sessions
.keys()
204 def get_collabs(self
, session
):
206 sessions
= self
._data
['sessions']
207 collabs
= sessions
[session
]['collabs'].keys()
213 def get_snaps(self
, session
, collab
):
214 if session
and collab
:
215 sessions
= self
._data
['sessions']
216 snaps
= sessions
[session
]['collabs'][collab
]['snaps']
222 def get_sounds(self
, session
, collab
):
223 if session
and collab
:
224 sessions
= self
._data
['sessions']
225 sounds
= sessions
[session
]['collabs'][self
._data
['user']]['sounds']
231 def _scan_snapshots(self
, session
):
233 files
= os
.listdir(session
)
234 pattern
= re
.compile(r
'\.ardour$')
236 if pattern
.search(file):
237 snaps
.append(file[0:-7])
241 def _scan_sounds(self
, session
):
242 sessions
= self
._data
['sessions']
247 print os
.path
.join (sessions
[session
]['path'],'interchange', session
, 'audiofiles')
248 files
= os
.listdir(os
.path
.join (sessions
[session
]['path'],'interchange', session
, 'audiofiles'))
250 files
= os
.listdir(os
.path
.join (session
,'sounds'))
251 pattern
= re
.compile(r
'\.peak$')
253 if not pattern
.search(file):
257 def __init__(self
, *args
):
258 self
._data
= shelve
.open(os
.path
.expanduser('~/.session_exchange'), 'c')
260 self
.debug_mode
= False
261 if len(self
._data
.keys()) < 1:
262 self
._data
['sessions'] = {}
263 self
._data
['user'] = ''
267 from twisted
.protocols
.basic
import FileSender
268 class FileSenderLimited(FileSender
):
269 def beginFileTransfer(self
, file, consumer
, limit
, transform
= None):
271 self
.consumer
= consumer
272 self
.CHUNK_SIZE
= limit
273 self
.transform
= transform
275 self
.consumer
.registerProducer(self
, False)
276 self
.deferred
= defer
.Deferred()
279 def resumeProducing(self
):
281 chunk
= self
.file.read(self
.CHUNK_SIZE
)
284 chunk
= self
.transform(chunk
)
286 self
.consumer
.write(chunk
)
287 self
.lastSent
= chunk
[-1]
289 self
.consumer
.unregisterProducer()
290 self
.deferred
.callback(self
.lastSent
)
293 from twisted
.protocols
.basic
import LineReceiver
294 class ExchangeServer (LineReceiver
):
298 def error(self
, message
):
299 self
.sendLine("ERROR")
300 self
.sendLine(message
)
301 self
.transport
.loseConnection()
303 def connectionLost(self
, reason
):
304 print "server: connection lost: ", reason
306 def connectionMade(self
):
307 print "server: connection made"
309 def lineReceived(self
, data
):
310 print "server: ", data
312 if self
.state
== "SESSION":
313 if g_data
.get_sessions().count(data
):
314 self
.session_name
= data
318 self
.error(data
+ " doesn't exist on server")
319 elif self
.state
== "SNAPSHOT":
320 if g_data
.get_snaps(self
.session_name
, g_data
.get_user()).count(data
):
321 filename
= g_data
.get_session_path(self
.session_name
)+data
+'.ardour'
323 self
.sendLine(str(os
.stat(filename
).st_size
))
325 self
.file = open(filename
, 'r')
326 file_sender
= FileSender()
327 cb
= file_sender
.beginFileTransfer(self
.file, self
.transport
)
328 cb
.addCallback(self
.file_done
)
330 self
.error("snapshot: " + data
+ " doesn't exist on server")
331 elif self
.state
== "SOUNDFILE" or self
.state
== "SOUNDFILE_HEADER":
332 if g_data
.get_sounds(self
.session_name
, g_data
.get_user()).count(data
):
333 filename
= g_data
.get_session_path(self
.session_name
)+"/interchange/"+self
.session_name
+"/audiofiles/"+data
335 if self
.state
== "SOUNDFILE":
336 self
.sendLine(str(os
.stat(filename
).st_size
))
337 else: #SOUNDFILE_HEADER
338 header_size
= get_header_size(filename
)
340 self
.sendLine(str(header_size
))
342 self
.error('soundfile: ' + data
+ 'doesn\'t have "data" chunk')
344 self
.file = open(filename
, 'r')
345 if self
.state
== "SOUNDFILE":
346 file_sender
= FileSender()
347 cb
= file_sender
.beginFileTransfer(self
.file, self
.transport
)
348 else: # SOUNDFILE_HEADER
349 file_sender
= FileSenderLimited()
350 cb
= file_sender
.beginFileTransfer(self
.file, self
.transport
, header_size
)
351 cb
.addCallback(self
.file_done
)
353 self
.error("soundfile: " + data
+ "doesn't exist on server")
354 elif self
.state
== "SOUNDFILE_SIZE":
355 if g_data
.get_sounds(self
.session_name
, g_data
.get_user()).count(data
):
356 filename
= g_data
.get_session_path(self
.session_name
)+"/sounds/"+data
358 self
.sendLine(str(os
.stat(filename
).st_size
))
360 elif data
== "SESSION":
361 self
.state
= "SESSION"
362 elif data
== "SNAPS":
364 for snap
in g_data
.get_snaps(self
.session_name
, g_data
.get_user()):
368 elif data
== "SNAPSHOT":
369 self
.state
= "SNAPSHOT"
370 elif data
== "SOUNDFILE":
371 self
.state
= "SOUNDFILE"
372 elif data
== "SOUNDFILE_HEADER":
373 self
.state
= "SOUNDFILE_HEADER"
374 elif data
== "SOUNDFILE_SIZE":
375 self
.state
= "SOUNDFILE_SIZE"
377 def file_done(self
, data
):
378 print "server: file done"
382 class ExchangeServerFactory(protocol
.ServerFactory
):
383 protocol
= ExchangeServer
388 class ExchangeClient (LineReceiver
):
389 def __init__(self
, session_name
, collab_name
, snap_name
, debug_mode
):
390 self
.session_name
= session_name
391 self
.collab_name
= collab_name
392 self
.snap_name
= snap_name
393 self
.debug_mode
= debug_mode
396 def connectionLost(self
, reason
):
397 g_display
.show_status("Connection lost")
399 def connectionMade(self
):
400 g_display
.show_status("Connection made")
401 self
.state
= "SESSION"
402 self
.sendLine("SESSION")
403 self
.sendLine(self
.session_name
)
405 def rawDataReceived(self
, data
):
406 self
.file.write(data
)
407 self
.received
+= len(data
)
408 print self
.received
, self
.filesize
409 if self
.received
>= self
.filesize
:
412 g_data
.rescan_session(self
.session_name
)
413 if self
.state
== "SNAPSHOT":
414 self
.sounds
= get_sound_list(self
.filename
)
418 self
.state
= "SOUNDFILE_HEADER"
419 self
.sendLine("SOUNDFILE_HEADER")
421 self
.state
= "SOUNDFILE"
422 self
.sendLine("SOUNDFILE")
423 self
.sendLine(self
.sounds
[self
.sound_index
])
425 self
.transport
.loseConnection()
426 elif self
.state
== "SOUNDFILE":
427 self
.sound_index
+= 1
428 if self
.sound_index
> len(self
.sounds
)-1:
429 self
.transport
.loseConnection()
431 self
.sendLine("SOUNDFILE")
432 self
.sendLine(self
.sounds
[self
.sound_index
])
433 elif self
.state
== "SOUNDFILE_HEADER":
434 self
.state
= "SOUNDFILE_SIZE"
435 self
.sendLine("SOUNDFILE_SIZE")
436 self
.sendLine(self
.sounds
[self
.sound_index
])
438 def lineReceived(self
, data
):
439 print "client: ", data
444 if self
.state
== "SESSION":
446 self
.state
= "SNAPSHOT"
447 self
.sendLine("SNAPSHOT")
448 self
.sendLine(self
.snap_name
)
451 self
.sendLine("SNAPS")
452 elif self
.state
== "SNAPS":
453 self
.transport
.loseConnection()
454 elif self
.state
== "SNAPSHOT":
456 self
.filename
= g_data
.get_session_path(self
.session_name
)+'/'+self
.snap_name
+'.ardour'
457 self
.file = open(self
.filename
, 'w')
459 elif self
.state
== "SOUNDFILE" or self
.state
== "SOUNDFILE_HEADER":
461 self
.filename
= g_data
.get_session_path(self
.session_name
)+"/interchange/"+self
.session_name
+"/audiofiles/"+self
.sounds
[self
.sound_index
]
462 self
.file = open(self
.filename
, 'w')
464 elif self
.state
== "ERROR":
465 raise_error(data
, g_display
.window
)
466 elif self
.state
== "SNAPS":
467 g_data
.add_snap(self
.session_name
, self
.collab_name
, data
)
468 elif self
.state
== "SNAPSHOT":
469 self
.filesize
= int(data
)
470 elif self
.state
== "SOUNDFILE":
471 self
.filesize
= int(data
)
472 elif self
.state
== "SOUNDFILE_HEADER":
473 self
.filesize
= int(data
)
474 elif self
.state
== "SOUNDFILE_SIZE":
475 append_empty_data(self
.filename
, int(data
))
476 self
.sound_index
+= 1
477 if self
.sound_index
> len(self
.sounds
)-1:
478 self
.transport
.loseConnection()
480 self
.state
= "SOUNDFILE_HEADER"
481 self
.sendLine("SOUNDFILE_HEADER")
482 self
.sendLine(self
.sounds
[self
.sound_index
])
484 class ExchangeClientFactory(protocol
.ClientFactory
):
485 def buildProtocol(self
, addr
):
486 return ExchangeClient(self
.session_name
, self
.collab_name
, self
.snap_name
, self
.debug_mode
)
488 def clientConnectionFailed(self
, connector
, reason
):
489 raise_error('Connection failed: ' + reason
.getErrorMessage(), g_display
.window
)
490 g_display
.show_status('Connection failed')
492 def __init__(self
, session_name
, collab_name
, snap_name
, debug_mode
):
493 self
.session_name
= session_name
494 self
.collab_name
= collab_name
495 self
.snap_name
= snap_name
496 self
.debug_mode
= debug_mode
498 class HelperWin(object):
499 def delete_me(self
, window
):
502 class Preferences(HelperWin
):
504 self
.window
= gtk
.Window(gtk
.WINDOW_TOPLEVEL
)
505 self
.window
.set_title('Preferences')
506 self
.window
.connect('destroy', self
.delete_me
)
507 self
.window
.set_position(gtk
.WIN_POS_MOUSE
)
509 main_box
= gtk
.VBox()
510 self
.window
.add(main_box
)
513 label1
= gtk
.Label("User")
514 self
.user
= gtk
.Entry()
515 self
.user
.set_text(g_data
.get_user())
516 hbox1
.pack_start(label1
)
517 hbox1
.pack_start(self
.user
)
518 main_box
.pack_start(hbox1
)
520 ok_btn
= gtk
.Button("Ok")
521 ok_btn
.connect('clicked', self
.ok_clicked
)
522 main_box
.pack_start(ok_btn
)
524 self
.window
.show_all()
526 def ok_clicked(self
, btn
):
527 g_data
.set_user(self
.user
.get_text())
528 self
.window
.hide_all()
531 self
.window
.show_all()
533 class AddCollaborator(HelperWin
):
534 def __init__(self
, session
):
535 self
.session_name
= session
537 self
.window
= gtk
.Window(gtk
.WINDOW_TOPLEVEL
)
538 self
.window
.set_title('Fetch Session')
539 self
.window
.connect('destroy', self
.delete_me
)
540 self
.window
.set_position(gtk
.WIN_POS_MOUSE
)
542 main_box
= gtk
.VBox()
543 self
.window
.add(main_box
)
546 label0
= gtk
.Label("Collaborator")
547 self
.collab
= gtk
.Entry()
548 self
.collab
.connect('key-release-event', self
.key_press
)
549 hbox0
.pack_start(label0
)
550 hbox0
.pack_start(self
.collab
)
551 main_box
.pack_start(hbox0
)
554 label1
= gtk
.Label("IP Address")
555 self
.address
= gtk
.Entry()
556 self
.address
.connect('key-release-event', self
.key_press
)
557 hbox1
.pack_start(label1
)
558 hbox1
.pack_start(self
.address
)
559 main_box
.pack_start(hbox1
)
562 label2
= gtk
.Label("Port Number")
563 self
.port
= gtk
.Entry()
564 self
.port
.connect('key-release-event', self
.key_press
)
565 self
.port
.set_text(str(g_data
.port
))
566 hbox2
.pack_start(label2
)
567 hbox2
.pack_start(self
.port
)
568 main_box
.pack_start(hbox2
)
571 label3
= gtk
.Label("Username")
572 label3
.set_sensitive(False)
573 self
.username
= gtk
.Entry()
574 self
.username
.set_sensitive(False)
575 hbox3
.pack_start(label3
)
576 hbox3
.pack_start(self
.username
)
577 main_box
.pack_start(hbox3
)
580 label4
= gtk
.Label("Password")
581 label4
.set_sensitive(False)
582 self
.password
= gtk
.Entry()
583 self
.password
.set_sensitive(False)
584 hbox4
.pack_start(label4
)
585 hbox4
.pack_start(self
.password
)
586 main_box
.pack_start(hbox4
)
588 self
.ok_btn
= gtk
.Button(gtk
.STOCK_OK
)
589 self
.ok_btn
.set_use_stock(True)
590 self
.ok_btn
.connect('clicked', self
.ok_clicked
)
591 self
.ok_btn
.set_sensitive(False)
592 main_box
.pack_start(self
.ok_btn
)
594 self
.window
.show_all()
596 def key_press(self
, event
, data
):
597 if self
.collab
.get_text() and self
.address
.get_text() and self
.port
.get_text():
598 self
.ok_btn
.set_sensitive(True)
600 self
.ok_btn
.set_sensitive(False)
603 def ok_clicked(self
, btn
):
604 self
.window
.hide_all()
605 g_data
.add_collab(self
.session_name
, self
.collab
.get_text(), self
.address
.get_text(), int(self
.port
.get_text()))
606 self
.collab
.set_text('')
607 self
.address
.set_text('')
608 self
.port
.set_text('')
609 self
.username
.set_text('')
610 self
.password
.set_text('')
613 self
.window
.show_all()
615 class ArdourShareWindow(object):
616 def menuitem_cb(self
, window
, action
, widget
):
617 print self
, window
, action
, widget
619 def add_collaborator_cb(self
, window
, action
, widget
):
621 self
.add_session
= AddCollaborator(self
.session
)
623 def fetch_snapshot_cb(self
, window
, action
, widget
):
624 if self
.session
and self
.collab
and self
.collab
!= g_data
.get_user():
625 client
= ExchangeClientFactory(self
.session
, self
.collab
, self
.snap
, g_data
.debug_mode
)
626 reactor
.connectTCP(g_data
.get_collab_ip(self
.session
, self
.collab
), g_data
.port
, client
)
628 def preferences_cb(self
, window
, action
, widget
):
629 self
.preferences
= Preferences()
631 def add_session_ok_file_btn_clicked(self
, w
):
632 filename
= self
.file_sel
.get_filename()
633 if filename
.endswith(".ardour"):
634 g_data
.add_session(filename
[0:filename
.rfind("/")+1])
635 self
.update_session_view()
637 raise_error("Not an Ardour session", self
.window
)
638 self
.file_sel
.destroy()
640 def add_session_cb(self
, window
, action
, widget
):
641 if g_data
.get_user():
642 self
.file_sel
= gtk
.FileSelection("Add Session...")
643 self
.file_sel
.ok_button
.connect("clicked", self
.add_session_ok_file_btn_clicked
)
644 self
.file_sel
.cancel_button
.connect("clicked", lambda w
: self
.file_sel
.destroy())
645 self
.file_sel
.connect("destroy", lambda w
: self
.file_sel
.destroy())
648 raise_error("Set the user name in the preferences first", self
.window
)
650 def create_session_cb(self
, window
, action
, widget
):
651 if g_data
.get_user():
652 self
.file_sel
= gtk
.FileSelection("Create Session...")
653 self
.file_sel
.ok_button
.connect("clicked", self
.create_file_ok_btn_clicked
)
654 self
.file_sel
.cancel_button
.connect("clicked", lambda w
: self
.file_sel
.destroy())
655 self
.file_sel
.connect("destroy", lambda w
: self
.file_sel
.destroy())
658 raise_error("Set the user name in the preferences first", self
.window
)
660 def create_file_ok_btn_clicked(self
, w
):
661 filename
= self
.file_sel
.get_filename()
662 if len(filename
) > 0:
663 g_data
.create_session(filename
)
664 self
.update_session_view()
666 raise_error("Not an Ardour session", self
.window
)
667 self
.file_sel
.destroy()
669 def update_session_view(self
):
670 self
.session_model
.clear()
671 for session
in g_data
.get_sessions():
672 self
.session_model
.set(self
.session_model
.append(), 0, session
)
674 def update_collab_view(self
):
675 self
.collab_model
.clear()
676 for collab
in g_data
.get_collabs(self
.session
):
677 self
.collab_model
.set(self
.collab_model
.append(), 0, collab
)
679 def update_snap_view(self
):
680 self
.snap_model
.clear()
681 for snap
in g_data
.get_snaps(self
.session
, self
.collab
):
682 self
.snap_model
.set(self
.snap_model
.append(), 0, snap
)
684 def cb_session_selection_changed(self
, selection_object
):
686 selection_object
.selected_foreach(lambda model
, path
, iter, sel
= selected
: sel
.append(path
))
688 self
.session
= self
.session_model
[x
][0]
689 self
.selected_type
= "session"
690 self
.update_collab_view()
692 def cb_collab_selection_changed(self
, selection_object
):
694 selection_object
.selected_foreach(lambda model
, path
, iter, sel
= selected
: sel
.append(path
))
696 self
.collab
= self
.collab_model
[x
][0]
697 self
.selected_type
= "collab"
698 self
.update_snap_view()
700 def cb_snap_selection_changed(self
, selection_object
):
702 selection_object
.selected_foreach(lambda model
, path
, iter, sel
= selected
: sel
.append(path
))
704 self
.snap
= self
.snap_model
[x
][0]
705 self
.selected_type
= "snap"
707 def delete_cb(self
, window
, action
, widget
):
708 if self
.selected_type
== "session":
709 g_data
.delete_session(self
.session
)
713 elif self
.selected_type
== "collab":
714 g_data
.delete_collab(self
.session
, self
.collab
)
717 elif self
.selected_type
== "snap":
718 g_data
.delete_snap(self
.session
, self
.collab
, self
.snap
)
721 self
.update_session_view()
722 self
.update_collab_view()
723 self
.update_snap_view()
724 self
.selected_type
= ""
726 def show_status(self
, text
):
727 mid
= self
.status_bar
.push(self
._status
_cid
, text
)
729 self
.status_bar
.remove(self
._status
_cid
, self
._status
_mid
)
730 self
._status
_mid
= mid
733 self
.selected_type
= ""
735 self
.collab
= g_data
.get_user()
742 self
.window
= gtk
.Window(gtk
.WINDOW_TOPLEVEL
)
743 self
.window
.set_title('Session Exchange')
744 self
.window
.set_size_request(400, 200)
745 self
.window
.connect('destroy', lambda win
: gtk
.main_quit())
746 self
.window
.set_position(gtk
.WIN_POS_MOUSE
)
748 accel_group
= gtk
.AccelGroup()
749 self
.window
.add_accel_group(accel_group
)
751 main_box
= gtk
.VBox()
752 self
.window
.add(main_box
)
755 ('/_File', None, None, 0, '<Branch>'),
756 ('/File/_Add Session...','<control>A', self
.add_session_cb
, 0, ''),
757 ('/File/Create _Session...', '<control>S', self
.create_session_cb
, 0, ''),
758 ('/File/sep1', None, None, 0, '<Separator>'),
759 ('/File/_Quit', '<control>Q', gtk
.main_quit
, 0, '<StockItem>', gtk
.STOCK_QUIT
),
760 ('/_Edit', None, None, 0, '<Branch>' ),
761 ('/Edit/Cu_t', '<control>X', self
.menuitem_cb
, 0, '<StockItem>', gtk
.STOCK_CUT
),
762 ('/Edit/_Copy', '<control>C', self
.menuitem_cb
, 0, '<StockItem>', gtk
.STOCK_COPY
),
763 ('/Edit/_Paste', '<control>V', self
.menuitem_cb
, 0, '<StockItem>', gtk
.STOCK_PASTE
),
764 ('/Edit/_Delete', None, self
.delete_cb
, 0, '<StockItem>', gtk
.STOCK_DELETE
),
765 ('/Edit/sep1', None, None, 0, '<Separator>'),
766 ('/Edit/Add Colla_borator...','<control>B', self
.add_collaborator_cb
,0,''),
767 ('/Edit/_Fetch Snapshot','<control>F', self
.fetch_snapshot_cb
,0,''),
768 ('/Edit/sep1', None, None, 0, '<Separator>'),
769 ('/Edit/_Preferences...','<control>P', self
.preferences_cb
, 0, '')
772 #need to hold a reference to the item_factory or the menubar will disappear.
773 self
.item_factory
= gtk
.ItemFactory(gtk
.MenuBar
, '<main>', accel_group
)
774 self
.item_factory
.create_items(menu_items
, self
.window
)
775 main_box
.pack_start(self
.item_factory
.get_widget('<main>'), False)
779 pane1
.pack2(pane2
, True, False)
781 scroll1
= gtk
.ScrolledWindow()
782 scroll1
.set_policy(gtk
.POLICY_AUTOMATIC
, gtk
.POLICY_AUTOMATIC
)
783 pane1
.pack1(scroll1
, True, False)
784 scroll2
= gtk
.ScrolledWindow()
785 scroll2
.set_policy(gtk
.POLICY_AUTOMATIC
, gtk
.POLICY_AUTOMATIC
)
786 pane2
.pack1(scroll2
, True, False)
787 scroll3
= gtk
.ScrolledWindow()
788 scroll3
.set_policy(gtk
.POLICY_AUTOMATIC
, gtk
.POLICY_AUTOMATIC
)
789 pane2
.pack2(scroll3
, True, False)
791 self
.session_model
= gtk
.ListStore(gobject
.TYPE_STRING
)
792 view1
= gtk
.TreeView(self
.session_model
)
793 column1
= gtk
.TreeViewColumn('Sessions', gtk
.CellRendererText(), text
=0)
794 view1
.append_column(column1
)
795 self
.session_selection
= view1
.get_selection()
796 self
.session_selection
.connect("changed", self
.cb_session_selection_changed
)
799 self
.update_session_view()
801 self
.collab_model
= gtk
.ListStore(gobject
.TYPE_STRING
)
802 view2
= gtk
.TreeView(self
.collab_model
)
803 column2
= gtk
.TreeViewColumn('Collaborators', gtk
.CellRendererText(), text
=0)
804 view2
.append_column(column2
)
805 self
.collab_selection
= view2
.get_selection()
806 self
.collab_selection
.connect("changed", self
.cb_collab_selection_changed
)
809 self
.snap_model
= gtk
.ListStore(gobject
.TYPE_STRING
)
810 view3
= gtk
.TreeView(self
.snap_model
)
811 column3
= gtk
.TreeViewColumn('Snapshots', gtk
.CellRendererText(), text
=0)
812 view3
.append_column(column3
)
813 self
.snap_selection
= view3
.get_selection()
814 self
.snap_selection
.connect("changed", self
.cb_snap_selection_changed
)
817 main_box
.pack_start(pane1
, True, True)
819 self
.status_bar
= gtk
.Statusbar()
820 main_box
.pack_start(self
.status_bar
, False)
821 self
._status
_cid
= self
.status_bar
.get_context_id('display')
822 self
._status
_mid
= ''
824 self
.window
.show_all()
829 -n, --no-server Only act as a client
830 -p, --port <port number> Defaults to 8970
831 -d, --debug Infers audio files. For debugging Ardour.
832 -v, --version Version
838 opts
, args
= getopt
.getopt(sys
.argv
[1:], "hp:ndv", ["help", "port=", "no-server", "debug", "version"])
839 except getopt
.GetoptError
:
844 if o
in ("-h", "--help"):
846 if o
in ("-d", "--debug"):
847 g_display
.window
.set_title('Session Exchange: Debug Mode')
848 g_data
.debug_mode
= True
849 if o
in ("-p", "--port"):
851 if o
in ("-n", "--no-server"):
853 if o
in ("-v", "--version"):
859 reactor
.listenTCP(g_data
.port
, ExchangeServerFactory())
860 except twisted
.internet
.error
.CannotListenError
:
861 print "Can not listen on a port number under 1024 unless run as root"
870 g_display
= ArdourShareWindow()
872 if __name__
== '__main__':