#
# Window with progress bars in :-,
#
import gtk
import threading

class ProgressOutput(gtk.HBox):
	def __init__(self, progress_win, user):
		gtk.HBox.__init__(self)
		self.bar = gtk.ProgressBar()
		self.pack_start(self.bar)
		self.bar.show()
		self.bar.set_fraction(0.0)
		self.bar.set_text("")
		
		#button = gtk.Button(_("Abort"))
		#self.pack_start(button)
		#button.connect("clicked", self.set_abort)
		#button.show()
		
		self.progress_win = progress_win
		
		self.lock = threading.Lock()

		# Update these thingy periodically
		self.log_messages = []
		self.bar_message = None
		self.bar_position = None
		self.done = 0
		self.enabled = None
		self.do_abort = 0

		user.timeout_add (self.timeout_update)
	
	def abort(self):
		return self.do_abort
	
	def set_abort(self, _button=None):
		print "Attempt progress abort"
		self.do_abort = 1
		
	def timeout_update(self, user):
		self.lock.acquire()

		# Bar greyed out
		if self.enabled != None:
			self.bar.set_sensitive(self.enabled)
			self.enabled = None

		# Print pending log messages
		while len(self.log_messages) != 0:
			self.progress_win.msg_print(self.log_messages[0])
			del self.log_messages[0]

		if self.bar_position != None:
			self.bar.set_fraction(self.bar_position)
			self.bar_position = None

		if self.bar_message != None:
			self.bar.set_text(self.bar_message)
			self.bar_message = None
		
		if self.done == 1:
			# No more update() calls
			user.timeout_remove (self.timeout_update)
		self.lock.release()

	def log_msg(self, msg):
		self.lock.acquire()
		self.log_messages.append(msg)
		self.lock.release()
	
	def bar_msg(self, msg):
		self.lock.acquire()
		self.bar_message = msg
		self.lock.release()
	
	def bar_pos(self, pos):
		self.lock.acquire()
		self.bar_position = pos
		self.lock.release()
	
	def bar_enable(self, toggle):
		self.lock.acquire()
		self.enabled = toggle
		self.lock.release()
	
	def finished(self):
		# call when you're finished using this progressbar
		self.lock.acquire()
		self.done = 1
		self.lock.release()

class ProgressWin:
 	def silence_output(self, _a=None):
 		# If threads continue to write stuff to the window
 		# after the user has closed it we segfault. Prevent this.
 		# There is probably a good way... like
 		# window->dont_let_user_close_me = 1...
 		self.window_closed = 1
 
	def toggle_text(self, _a):
		if self.text_hidden == 1:
			self.swin.show()
			self.text_hidden = 0
		else:
			self.swin.hide()
			self.text_hidden = 1
		# window should contract
		self.win.queue_resize()
 
	def close(self, _a=None):
		self.silence_output()
		self.win.destroy()
 
	def __init__(self, title, user, hidetext=None, parent_win=None):
		"""
		Set hidetext to the desired label of button to
		show/hide text widget.
		"""
		self.user = user

		self.win = gtk.Dialog()
		self.win.set_title(title)
 		self.win.connect("destroy", self.silence_output)
		if parent_win:
			self.win.set_transient_for (parent_win)

		self.win.vbox.set_spacing(5)
		self.win.vbox.set_border_width(5)
 
		self.window_closed = 0

		self.win.action_area.set_border_width(0)
		button_box = gtk.HBox(spacing=5)
		self.win.action_area.pack_start(button_box)
		button_box.show()
		
		self.close_button = gtk.Button(stock="gtk-close")
		self.close_button.connect("clicked", self.close)
		button_box.pack_end(self.close_button, expand=False)
		self.close_button.show()

		self.swin = gtk.ScrolledWindow()
		self.swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
		self.swin.set_shadow_type(gtk.SHADOW_IN)
		self.win.vbox.pack_end(self.swin)

		if hidetext == None:
			self.swin.show()
			self.text_hidden = 0
		else:
			self.details_button = gtk.Button(" "+hidetext+" ")
			self.details_button.connect("clicked", self.toggle_text)
			button_box.pack_end(self.details_button, expand=False)
			self.details_button.show()
			self.text_hidden = 1

		self.textview = gtk.TextView()
		self.textview.set_editable(False)
		self.textview.show()
		self.swin.add(self.textview)

		self.win.show()

		# XXX Strange bug(?) in gtk makes first line default colour
		# and therefore possibly invisible.
		self.msg_print("")

	def msg_print(self, message):
		"""
		Push a message onto the gtk.Text object.
		"""
		textbuffer = self.textview.get_buffer()
		iter = textbuffer.get_end_iter()
		if not self.window_closed:
			textbuffer.insert(iter, message+"\n")

	def get_progress_bar(self, thread=None):
		"""
		Returns a progress bar object. access it as you
		would normally and .destroy() it when done.
		If thread!=None a box will be available to
		kill the thread, too.
		This doesn't work. Threads can't be killed :-(
		"""
		bar = ProgressOutput(self, self.user)
		self.win.vbox.pack_start(bar, expand=False)
		bar.show()
		return bar



syntax highlighted by Code2HTML, v. 0.9.1