#!/usr/bin/env python

#    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 3 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, see <http://www.gnu.org/licenses/>.

# TerminalScreenlet (c) spdf (aka Mark Hayes) 2008 <mcleodm@gmail.com>

import screenlets
from screenlets.options import BoolOption, StringOption, FloatOption, IntOption, ColorOption, FileOption
import gobject
import gtk
import cairo
import vte
import gconf
import os

# use gettext for translation
import gettext

_ = screenlets.utils.get_translator(__file__)

def tdoc(obj):
	obj.__doc__ = _(obj.__doc__)
	return obj

@tdoc

class TerminalScreenlet (screenlets.Screenlet):
   """A Terminal Screenlet"""
   __name__ = 'TerminalScreenlet'
   __version__ = '0.1.11'
   __author__ = 'spdf'
   __desc__ = __doc__
   __timeout__ = None 


   # GConf Profile dir for gnome-terminal
   GCONF_PROFILE_DIR = "/apps/gnome-terminal/profiles/Default"
   gconf_client = gconf.client_get_default() 

   transparent = False
   vte_transparent = False
   background = '' 
   use_back = False
   trans_value = 1.0 
   vte_trans_value = 1.0
   border_width = 5 
   border_color = [1.0, 1.0, 1.0, 1.0]
   foreground_color = [1.0, 1.0, 1.0, 1.0]
   background_color = [0, 0, 0, 1.0]
   font_name = ''
   term_width = 640
   term_height = 480 
   use_gconf_cols = False
   launch_app = ''
   scrollback_lines = 250

   def __init__ (self, **keyword_args):
      # Create screenlet
      screenlets.Screenlet.__init__(self, is_widget=False, width=640, height=480, uses_theme=False, **keyword_args)

      # prep gconf
      self.gconf_client.add_dir(self.GCONF_PROFILE_DIR, gconf.CLIENT_PRELOAD_RECURSIVE) 
      self.gconf_client.notify_add(self.GCONF_PROFILE_DIR, self.on_gconf_notification)

      # Options
      self.add_options_group(_('Options'), _('Terminal Options'))
      self.add_option(IntOption(_('Options'),'scrollback_lines', self.scrollback_lines,_('Scrollback Lines'),'',min=0,max=2000,increment=10))
      self.add_option(BoolOption(_('Options'),'transparent', self.transparent, _('Transparent Screenlet'), '')) 
      self.add_option(FloatOption(_('Options'),'trans_value', self.trans_value,_('Amount'), '', min=0.1, max=1.0, increment=0.1,digits=2))
      self.add_option(BoolOption(_('Options'),'vte_transparent', self.vte_transparent, _('Transparent Terminal'), ''))
      self.add_option(FloatOption(_('Options'),'vte_trans_value', self.vte_trans_value,_('Amount'), '', min=0, max=1.0, increment=0.1,digits=2))
      self.add_option(BoolOption(_('Options'),'use_back', self.use_back, _('Use Background'), '')) 
      self.add_option(StringOption(_('Options'),'background',self.background,_('Path to Image'),_('Full path to image file')))
      self.add_option(StringOption(_('Options'),'launch_app',self.launch_app,_('Startup Command'),''))
      
      # Colours
      self.add_options_group(_('Colours'), _('Terminal Colours'))
      self.add_option(ColorOption(_('Colours'),'border_color', self.border_color, _('Border Colour'),''))
      self.add_option(ColorOption(_('Colours'),'foreground_color', self.foreground_color, _('Foreground Colour'),''))
      self.add_option(ColorOption(_('Colours'),'background_color', self.background_color, _('Background Colour'),''))
      self.add_option(BoolOption(_('Colours'),'use_gconf_cols', self.use_gconf_cols, _('Use gconf palette settings'),_('Uses palette from default gnome-terminal profile'))) 

      # Sizing
      self.add_options_group(_('Sizing'), _('Sizing/Border Options'))
      self.add_option(IntOption(_('Sizing'),'term_width', self.term_width,_('Width'),'',min=20, max=2000,increment=10))
      self.add_option(IntOption(_('Sizing'),'term_height', self.term_height,_('Height'),'',min=20, max=2000,increment=10)) 
      self.add_option(IntOption(_('Sizing'),'border_width', self.border_width, _('Border Width'),'',min=0,max=25))

      # Fonts 
      self.add_options_group(_('Fonts'), _('Font Options'))
      self.add_option(StringOption(_('Fonts'),'font_name',self.font_name,_('Font String'),''))

      # Terminal
      self.vbox = gtk.VBox()
      self.terminal = vte.Terminal()
      self.vbox.add(self.terminal)
      self.vbox.set_size_request(self.width,self.height)
      self.window.add (self.vbox)
      self.vbox.show_all()
      self.vbox.set_border_width(self.border_width)

      # Signal connect
      self.terminal.connect ("child-exited", lambda term: term.fork_command())
      self.terminal.connect ("popup-menu", self.on_vte_popup_menu)
      self.terminal.connect ("button-press-event", self.on_vte_button_press)

      # Fork terminal
      self.terminal.fork_command()

   def on_gconf_notification(self, client, conn_id, entry, value):
      self.vte_set_colours()

   def gconf_get_str(self, key, default = ""):
      val = self.gconf_client.get(key)
      if val is not None and val.type == gconf.VALUE_STRING:
         return val.get_string()
      else:
         return default 

   def show_font_dialog (self):
      font_sel = gtk.FontSelectionDialog(_("Select a Font - Cancel sets default system font"))
      font_sel.set_font_name(self.font_name)
      resp = font_sel.run()
      if (resp == gtk.RESPONSE_OK):
         # Apply
         self.font_name = font_sel.get_font_name()
      elif (resp == gtk.RESPONSE_CANCEL):
         # Defaults to system specified font
         self.font_name = ''
      font_sel.destroy() 

   def vte_set_background_image (self):
      if (self.use_back):
         try: self.terminal.set_background_image_file(self.background)
         except: pass
      else:
         try: self.terminal.set_background_image_file("")
         except: pass 

   def vte_set_opacity (self, value):
      opacity = int(value * 65535)
      self.terminal.set_opacity(opacity) 

      # background colour has to change (even slightly) for this to have any effect without restart, this is the workaround. 
      self.terminal.set_colors(gtk.gdk.color_parse ("#ABCDEF"), gtk.gdk.color_parse ("#ABCDEF"), [])
      self.vte_set_colours()

   def vte_set_font (self, value):
      try: self.terminal.set_font_from_string(value)
      except: pass

   def vte_set_colours (self):
      if (self.use_gconf_cols):
         # Get palette from gconf, create list of gdk.Colors
         palette = self.gconf_get_str(self.GCONF_PROFILE_DIR + "/palette", "")
         gdk_palette = [] 
         for col in palette.split(':'):
            newcol = gtk.gdk.color_parse(col)
            gdk_palette.append(newcol)
         fg_colour = self.gconf_get_str(self.GCONF_PROFILE_DIR + "/foreground_color", "#FFFFFF")
         bg_colour = self.gconf_get_str(self.GCONF_PROFILE_DIR + "/background_color", "#000000")
         self.terminal.set_colors(gtk.gdk.color_parse (fg_colour), gtk.gdk.color_parse (bg_colour), gdk_palette)
      else:
         fg_colour = gtk.gdk.Color(int(self.foreground_color[0] * 65535), int(self.foreground_color[1] * 65535), int(self.foreground_color[2] * 65535))
         bg_colour = gtk.gdk.Color(int(self.background_color[0] * 65535), int(self.background_color[1] * 65535), int(self.background_color[2] * 65535))
         self.terminal.set_colors(fg_colour, bg_colour, [])

   def on_init(self):
      self.add_default_menuitems()
      if (self.use_back):
         self.vte_set_background_image()
      if (self.transparent):
         self.window.set_opacity(self.trans_value)
      if (self.vte_transparent):
         self.vte_set_opacity(self.vte_trans_value)
      self.terminal.feed_child('%s \n' % (self.launch_app))

   def on_draw (self, ctx):
      ctx.scale(self.scale, self.scale)
      ctx.save()
      ctx.rectangle(0,0,self.width,self.height)
      ctx.set_source_rgba(self.border_color[0], self.border_color[1], self.border_color[2], 1.0)
      ctx.fill()
      ctx.restore()

   def on_draw_shape (self, ctx):
      self.on_draw(ctx)

   def on_vte_popup_menu(self, term):
      self.do_popup()

   def on_vte_button_press(self, term, event):
      if event.button == 3:
         self.do_popup(event)
         return True 

   def do_popup(self, event = None):
      menu = self.create_popup_menu()
      if event is not None:
         menu.popup(None, None, None, event.button, event.time)
      else:
         menu.popup(None, None, None, 0, gtk.get_current_event_time())
         menu.select_first(False)        

   def create_popup_menu(self):
      menu = gtk.Menu()

      item = gtk.ImageMenuItem(gtk.STOCK_COPY)
      item.connect("activate", lambda menu_item: self.terminal.copy_clipboard())
      item.set_sensitive(self.terminal.get_has_selection())
      menu.append(item)

      item = gtk.ImageMenuItem(gtk.STOCK_PASTE)
      item.connect("activate", lambda menu_item: self.terminal.paste_clipboard())
      menu.append(item)

      item = gtk.SeparatorMenuItem()
      menu.append(item)
 
      item = gtk.ImageMenuItem(gtk.STOCK_PROPERTIES)
      item.connect("activate", lambda menu_item: self.show_options_dialog())
      menu.append(item)
        
      item = gtk.SeparatorMenuItem()
      menu.append(item)
      
      item = gtk.ImageMenuItem(gtk.STOCK_SELECT_FONT)
      item.connect("activate", lambda menu_item: self.show_font_dialog())
      menu.append(item)

      menu.show_all()
      return menu

   def __setattr__ (self, name, value):
      screenlets.Screenlet.__setattr__ (self, name, value)
      if name == 'transparent':
         if (value):
            self.window.set_opacity(self.trans_value)
         else:
            self.window.set_opacity(1)
      if name == 'vte_transparent':
         if (value):
            self.vte_set_opacity(self.vte_trans_value)
         else:
            self.vte_set_opacity(1)
      elif name == 'use_back':
         self.vte_set_background_image()
      elif name == 'background':
         self.vte_set_background_image()
      elif name == 'trans_value':
         if (self.transparent):
            self.window.set_opacity(self.trans_value)
      elif name == 'vte_trans_value':
         if (self.vte_transparent):
            self.vte_set_opacity(self.vte_trans_value)
      elif name == 'scale':
         try:
            self.vbox.set_size_request(int(self.width*value), int(self.height*value))
         except AttributeError:
            pass # Applet not yet fully created.
      elif name == 'border_width':
         self.vbox.set_border_width(value)
      elif (name == 'term_width'):
         self.width = value 
         self.window.set_size_request(int(self.width*self.scale),int(self.height*self.scale))
      elif (name == 'term_height'):
         self.height = value 
         self.window.set_size_request(int(self.width*self.scale),int(self.height*self.scale))
      elif name == 'border_color':
         self.redraw_canvas()
      elif name == 'background_color':
         self.vte_set_colours()
      elif name == 'foreground_color':
         self.vte_set_colours()
      elif name == 'font_name':
         self.vte_set_font(value)
      elif name == 'use_gconf_cols':
         self.vte_set_colours()
      elif name == 'scrollback_lines':
         self.terminal.set_scrollback_lines(value)
           

if __name__ == "__main__":
   #Create screenlet session
   import screenlets.session
   screenlets.session.create_session(TerminalScreenlet)
