#!/usr/bin/python
 
import wx
import win32clipboard as wcb
import win32con
import time
import CBThread as th
import optFrame
from wx.lib.wordwrap import wordwrap
 
_version = '0.9/10'
_dev_by = 'germaNRG'
_dev_on = '2010'
DEF_MAX_HISTORY_LENGHT = 10
 
_clip_err = '''Clipboard error\n
This type of data (FILE) isn't allowed to put into the clipboard.
Now, the clipboard is empty and you can select another history option.
The program will be continue normally.\n
'''
 
class MyTaskBarIcon(wx.TaskBarIcon):
    ''' The Task bar icon Main Class '''
    def __init__(self, parent):
        wx.TaskBarIcon.__init__(self)
        self.old = False
        self.history = []
        self.frame = parent
        self.id = parent.id
        self.tc_shown = -1 # How many text controls was being shown on the main frame
        self.show = -1
        self.inc_id = 199 # For the submenu buttons
        self.SetIcon(wx.Icon('cbh.png', wx.BITMAP_TYPE_PNG), 'CBHistory v1.0')
        self.Bind(wx.EVT_MENU, self.OnTaskBarActivate, id=100)
        self.Bind(wx.EVT_MENU, self.OnAbout, id=101)
        self.Bind(wx.EVT_MENU, self.OnOptions, id=102)
        #self.Bind(wx.EVT_MENU, self.OnTaskBarDeactivate, id=102)
        self.Bind(wx.EVT_MENU, self.OnHistoryPressed, id=103)
        self.Bind(wx.EVT_MENU, self.OnTaskBarClose, id=104)
        wx.EVT_TASKBAR_LEFT_DCLICK(self, self.OnTaskBarLeftDClick) # Left Double Click
        self.CreatePopupMenu()
        self.Handle_Clipboard()
 
    def CreatePopupMenu(self):
        ''' Create the right click menu. '''
        self.menu = wx.Menu("CBHistory v" + _version)
        self.menu.Append(100, 'Show main window')
        self.menu.Append(101, 'About CBH ...')
        #self.menu.Append(102, 'Hide the Main Window')
        self.menu.AppendSeparator()
        self.menu.Append(102, 'Options')
        # Create "History" Submenu
        self.hist = wx.Menu("Clipboard Data")
        if self.history:
            i = 0
            for x in self.history:
                if i < DEF_MAX_HISTORY_LENGHT:
                    clip = x[0]
                    #clip = clip[:15]
                    if x[2] == 'TEXT_UNICODE':
                        def_str = clip[:20]
                        hIcon = wx.ArtProvider.GetBitmap(wx.wx.ART_HELP_SETTINGS, wx.ART_TOOLBAR, (16,16))
                    elif x[2] == 'FILE_HDROP':
                        def_str = '(' + clip[:1] + ')' + clip[-14:]
                        hIcon = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_TOOLBAR, (16,16))
                    if len(x[0]) > 15: def_str += '  (...)'
                    hItem = wx.MenuItem(self.hist, x[1], def_str, clip)
                    hItem.SetBitmap(hIcon)
                    hItem.SetCheckable(True)
                    self.hist.AppendItem(hItem)
                    #self.hist.AppendCheckItem(x[1], def_str, clip)
                    self.Bind(wx.EVT_MENU, self.OnHistoryOption, id=x[1])
                    i += 1
            self.hist.Check(self.checked, True)
 
        self.menu.AppendMenu(103, 'History', self.hist)
        self.menu.AppendSeparator()
        self.menu.Append(104, 'Exit')
        return self.menu   
 
    def Handle_Clipboard(self):
        ''' Create the thread to manage and throw another threads. '''
        self.thread = th.KThread(target=self._create_threads)
        # The entire Python program exits when no alive non-daemon threads are left.
        self.thread.setDaemon(True)
        self.thread.start()
        #thread.kill()
 
    def _create_threads(self):
        ''' Root Thread '''
        while True:
            self.getClip = th.KThread(target=self.getClipboardData)
            self.getClip.start()
            time.sleep(3)
            self.getClip.kill()
 
    def getClipboardData(self):
        ''' Son thread get dat from the clipboard to history list and kill himself. '''
        data = ''
        wcb.OpenClipboard()
        if wcb.IsClipboardFormatAvailable(win32con.CF_UNICODETEXT):
            data = wcb.GetClipboardData(win32con.CF_UNICODETEXT)
            format = 'TEXT_UNICODE'
        if wcb.IsClipboardFormatAvailable(win32con.CF_HDROP):
            data = wcb.GetClipboardData(win32con.CF_HDROP)
            format = 'FILE_HDROP'
            data = data[0]
        if data:
            # Set textCtrl value on main frame 
            if self.frame.tc1.GetValue() != data:
                self.frame.tc1.SetValue(data)
                # Change a BitmapButton V to X or vic.
                self.frame.btn1.Show()
                self.frame.btn2.Hide()
                # Show a textctrl on main frame
                # Show first entry
                if self.tc_shown == -1:
                    self.frame.textControls[0].SetValue(data)
                    self.tc_shown = self.show = 0
                else:
                    # Moves old entries when new entry is arrived
                    while self.show >= 0:
                        val = self.frame.textControls[self.show].GetValue()
                        self.frame.textControls[self.show+1].SetValue(val)
                        self.show -= 1
                    self.frame.textControls[0].SetValue(data)
                # Show one more
                self.frame.textControls[self.tc_shown].Show()
                self.tc_shown += 1
                self.show = self.tc_shown
            # Set the checked prop. to the correctly option 
            for item in self.history:
                if data == item[0]:
                    old_id = item[1]
                    self.old = True
            if self.old:
                self.old = False
                self.checked = old_id
            else:
                self.history.insert(0, (data, self.inc_id, format))
                self.checked = self.inc_id
                self.inc_id += 1
        else:
            self.frame.btn2.Show()
            self.frame.btn1.Hide()
        wcb.CloseClipboard()
        data = ''  
 
    def OnTaskBarClose(self, event):
        ''' Close the program by parent and stop the threads.'''
        try: self.getClip.kill()
        except: pass
        self.thread.kill()
        #self.Destroy()
        self.frame.OnClose()
 
    def OnTaskBarActivate(self, event):
        ''' Show window '''
        if not self.frame.IsShown():
            self.frame.Show()
 
    def OnTaskBarDeactivate(self, event):
        ''' Hide window '''
        if self.frame.IsShown():
            self.frame.Hide()
 
    def OnHistoryPressed(self, event):
        pass
 
    def OnAbout(self, event):
        ''' Show about dialog on parent. '''
        #self.frame.menuAbout(event)
        self.ShowAbout()
 
    def ShowAbout(self):
        licenseText = '''       GNU GENERAL PUBLIC LICENSE
        Version 3, 29 June 2007
 
 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.'''
        # First we create and fill the info object
        info = wx.AboutDialogInfo()
        info.Name = "ClipBoard History"
        info.Version = _version
        info.Copyright = "(C) 2010"
        info.Description = wordwrap(
            "\"ClipBoard History \" program is a software program based on a simple "
            "TaskBar Icon. With that app you can have a custom lenght history clipboard "
            "for your system and can do changes on him."
 
            "\n\nClipBoard History has written all in python and has been developed"
            "by germaNRG under GNUGPLv3 license. "
            "see more on http://www.gnu.org/licenses/gpl-3.0.txt"
 
            "\n\nTo report a bug or make any suggestion you should  "
            "send it to germanpython@gmail.com",
            350, wx.ClientDC(self.frame))
        info.WebSite = ("http://devnewbies.blogspot.com", "CBH Home Page")
        info.Developers = [ _dev_by,
                            'germanpython@gmail.com']
 
        info.License = wordwrap(licenseText, 500, wx.ClientDC(self.frame))
 
        # Then we call wx.AboutBox giving it that info object
        wx.AboutBox(info)
 
    def OnOptions(self, event):
        ''' Show the options frame and deactivate the main frame. '''
        if not self.frame.IsShown():
            self.frame.Show()
        if self.frame.IsShown() and not self.frame.IsFrozen():
            self.frame.Freeze()
            self.frame.SetTransparent(150)
            of = optFrame.OptionsFrame(self.frame)
            of.Show(True)
            # The opt frame get the control of his parent frame.
            # Opt are destroyed by himself, so previously opt give back
            # the control for his parent using:
            #     parent.Thaw()
            #     parent.SetTransparent(255) # 0 - 255
 
 
    def OnTaskBarLeftDClick(self, event):
        ''' Hide/show the main window on double left click over
        the task bar icon. '''
        if self.frame.IsShown():
            self.frame.Hide()
        else:
            self.frame.Show()
            # To set the focus on the frame whin he has been shown.
            self.frame.Raise() 
 
    def OnHistoryOption(self, event):
        ''' When a SubMenu(self.hist) Option is selected. '''
        event_id =  event.GetId()
        # Save the format and data retrieves by the clipboard.
        for x in self.history:
            if event_id == x[1]:
                event_format = x[2]
                event_data = x[0]
 
        #print "<--- EVENT --->"
        #print ".getid: " + str(event.GetId())
        #iter = 0
        #while iter < len(self.history):
        #    if event_id == self.history[iter][1]:
        #        print 'You pressed on: ' + self.history[iter][0]
        #    iter += 1
 
        # Change the checked option 
        if self.checked != event_id:
            self.hist.Check(self.checked, False)
            self.checked = event_id
            #self.hist.Check(self.checked, True)
            # Put new data on the clipboard and close him.
            wcb.OpenClipboard()
            wcb.EmptyClipboard()
            if event_format == 'TEXT_UNICODE':
                wcb.SetClipboardData(win32con.CF_UNICODETEXT, event_data)
                self.hist.Check(self.checked, True)
                self.frame.tc1.SetValue(event_data)
            elif event_format == 'FILE_HDROP':
                # Raise an error when the user try to put a file on the clipboard.
                #wcb.SetClipboardData(win32con.CF_HDROP, event_data)
                print 'dentro'
                self._error(_clip_err)
                self.hist.Check(self.checked, True)
                self.frame.tc1.SetValue('')
            try: wcb.CloseClipboard()
            except: pass
 
    def _error(self, message):
        dlg = wx.MessageDialog(None, message, 'Clipboard Error',wx.OK | wx.ICON_ERROR | wx.CENTRE)
        dlg.ShowModal()