#!/usr/bin/env python

"""
v 6.3.5

kAnyRemote
KDE GUI for anyRemote - a bluetooth remote for your PC.

Copyright (C) 2007-2015 Mikhail Fedotov <anyremote@mail.ru>

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 2 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 ofF
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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
"""

import gettext
import glob
import httplib
import locale
import getopt
import os
import re
import signal
import socket
import SocketServer
import sys
import sys
import thread
import threading
import time
import datetime

#Translation stuff

#Get the local directory since we are not installing anything
dirpath = os.path.dirname(sys.argv[0])
local_path = os.path.realpath(os.path.join(dirpath,'mo'))

# try ../share/locale/ (Linux)
if not os.path.exists(local_path):
    local_path = os.path.realpath(os.path.join(dirpath,'../share/locale/'))

# try ../lib/locale/ (Sun)
if not os.path.exists(local_path):
    local_path = os.path.realpath(os.path.join(dirpath,'../lib/locale/'))

# last resort ... try /usr/share/locale
if not os.path.exists(local_path):
    local_path = os.path.realpath('/usr/share/locale/')

langs = []

lc = ''
encoding = ''

try:
    lc, encoding = locale.getdefaultlocale()
except ValueError, cmd:
    print 'Error: ',cmd,'\nCorrect $LANG or $LANGUAGE first !!!'
    sys.exit()

if lc:
    #If we have a default, it's the first in the list
    langs = [lc]

# Now lets get all of the supported languages on the system
language = os.environ.get('LANGUAGE', None)
if language:
    langs += language.split(":")

APP_NAME = "kanyremote"

gettext.bindtextdomain(APP_NAME, local_path)
gettext.textdomain(APP_NAME)

# Get the language to use
lang = gettext.translation(APP_NAME, local_path, languages=langs, fallback = True)

_ = lang.ugettext

try:
    from PyQt4.QtGui  import *
    from PyQt4.QtCore import *
except ImportError:
   print 'Install PyQt4 first !!!'
   sys.exit()

pybluez = True 
try:
    import bluetooth
except ImportError:
   pybluez = False

def _tr(string):
    ob = QObject()
    return ob.trUtf8(_(string))

#
# String constants (not all!)
#
AR_INSTALLED    = _tr('Installed')
AR_NOTINSTALLED = _tr('Not installed')

AR_NOINFO   = _tr('No information')
AR_AVAIL    = _tr('Available')
AR_NOTAVAIL = _tr('Not available')
AR_MANAGED  = _tr('Managed')
AR_RUNNING  = _tr('Running')

AR_CONN_DEV = _tr('Connecting to device')
AR_WAIT_OPS = _tr('Wait other operations to finish')

AR_TCP_PORT=_tr('TCP port')
AR_BT_PORT=_tr('Bluetooth channel')
AR_HTTP_PORT=_tr('HTTP port')


AR_DOWNLOADING=_tr('Downloading')
AR_J2ME_CHECK  = _tr('Checking J2ME client updates')
AR_NO_J2ME_UPD = _tr("No updates for J2ME client were found.")

AR_CODE_J2ME_UPD = 20014
AR_CODE_LOADED   = 20017

AR_FILE_DEVICES='anyremote-peers.conf'

signal.signal(signal.SIGINT, signal.SIG_DFL)
           
###############################################################################
#
# J2ME client uploader
# unified
#
###############################################################################
class JCUploader(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self) 

    def run(self):
        global debug,jup
        
        if debug: print 'JCUploader starting'
    
        self.run = True
        
        stopPBar()
        startPBar(AR_DOWNLOADING+' anyRemote-16.jad')
         
        ret = True
        
        jars = ["-16","-32","-48","-64","-128","","-nojsr82"]
        
        for sz in jars:
        
            for bi in ["", "b"]:
                
                # no big icons for these variants
                if bi == "b" and (sz == "" or sz == "-nojsr82"):
                    continue
                
                if self.run and ret:
                    ret = uploadJ2MEWebGui('anyRemote'+sz+bi+'.jad', True)

                if self.run and ret: 
                    ret = uploadJ2MEWebGui('anyRemote'+sz+bi+'.jar')
    
        if self.run: stopPBar()
        
        if debug: print 'JCUploader: upload done'
        
        jup = None

    def stop(self):
        global debug
        if debug: print 'stop JCUploader'
        
        self.run = False

def stopJCUploader():
    global jup
    try:
        if jup != None:
            jup.stop()
    except NameError:
        pass
    time.sleep(0.5)
    jup = None

##################################################################################
#
# J2ME client verifier
# unified
#
##################################################################################
class JCVerifier(threading.Thread):

    def __init__(self, force):
        threading.Thread.__init__(self) 
        self.anyway = force

    def run(self):
        global debug
        
        if debug: print 'JCVerifier starting'
        
        curdate = time.strftime("%d%m", time.gmtime())
        
        if self.anyway:
            startPBar(AR_J2ME_CHECK)
        else:
            try:
                f = open(os.environ.get("HOME")+os.sep+'.anyRemote'+os.sep+'j2me-client.checked', 'r')
                date = f.read() 
                f.close()        
                date = date.replace('\n','')
                    
                if debug: print 'JCVerifier',date,curdate
            
                if date == curdate:
                    if debug: print 'JCVerifier: already checked. Exiting'
                    self = None
                    return

            except IOError:
                pass
            
        if debug: print 'JCVerifier: check new version'

        os.system('echo \"'+curdate+'\" > $HOME/.anyRemote/j2me-client.checked')
        newver = checkJ2MEClientUpdate();
        
        if debug: print 'JCVerifier: upload done '+newver
        
        if self.anyway:    
            stopPBar()
        
        if newver == "":
            if self.anyway:
                infoMessage(AR_NO_J2ME_UPD)
        # newver == "-1" in case of connection absense
        elif newver != "-1": 
            codeMessage(AR_CODE_J2ME_UPD)
        
        self = None

##################################################################################
#
# Reader of cfg. files
# unified
#
##################################################################################
class CfgFileReader(threading.Thread):

    def __init__(self):
        global cfgFileReaderFlag
        
        threading.Thread.__init__(self) 
        
        cfgFileReaderFlag = True

    def run(self):
        global debug, cfgFileReaderFlag, cfgReader

        if debug: print 'CfgFileReader.run'
        
        clearAppsList()
        
        self.regExp  = re.compile("^[^a-zA-Z0-9]*Gui")
        self.regExpB  = re.compile("^[^a-zA-Z0-9%]*VERS[^=]*=.+$")
        self.regExpAT = re.compile("^[^a-zA-Z0-9%]*Device[^=]*=/dev/[a-zA-Z0-9]+$")
        
        t1 = datetime.datetime.now()
        
        numProcessed = 0
        for cfgDir in cfgReader.cfgDirs:
              
            if cfgDir == '':
                continue
            if debug: print 'Collect files in '+cfgDir
            
            if os.path.isfile(cfgDir):
                self.processOneFile(cfgDir)
                
                numProcessed = numProcessed+1
                codeMessage2(AR_CODE_LOADED, numProcessed)
                
            else:
                for root, dirs, files in os.walk(cfgDir):
                    
                     
                    if 'Utils' in dirs:
                       dirs.remove('Utils')
                       if debug: print 'skip dir',root+os.sep+'Utils'
                    if 'Icons' in dirs:
                       dirs.remove('Icons')
                       if debug: print 'skip dir',root+os.sep+'Icons'
                    if '.svn' in dirs:
                       dirs.remove('.svn')
                       if debug: print 'skip dir',root+os.sep+'.svn'
                    
                    for cfgFile in files:

                        nameext = cfgFile.split('.')
                        ext = nameext[len(nameext)-1]

                        if ext == 'png' or ext == 'sh' or ext == 'py' or ext == 'gz':
                            if debug: print 'Not a configuration file '+cfgFile
                            continue

                        self.processOneFile(root + os.sep + cfgFile)

                        numProcessed = numProcessed+1
                        codeMessage2(AR_CODE_LOADED, numProcessed)
        
        codeMessage2(AR_CODE_LOADED, -1)
        
        cfgFileReaderFlag = False
        
        t2 = datetime.datetime.now()
        #print "Load time ",(t2-t1)
            
    def processOneFile(self,cfgFile):
        global debug, cfgReader
        
        fd = None
        try:
            fd = open(cfgFile,'r')
        except IOError:
            pass
         
        if fd:
            aName    = None
            aInst    = ''
            aRun     = ''
            aIcon    = ''
            aType    = None
            aDesc    = ''
            aVers    = ''
            aModes   = ''
            aDevice  = ''
            aBemused = ''
        
            for line in fd:
        
                if self.regExp.match(line):
                    
                    p = re.search("^[^a-zA-Z0-9]*GuiAppName[^=]*=(.+)$", line)
                    if p != None:
                        aName = p.group(1)

                    p = re.search("^[^a-zA-Z0-9]*GuiAppBinary[^=]*=(.+)$", line)
                    if p != None:
                        aInst = p.group(1)
                    
                    p = re.search("^[^a-zA-Z0-9]*GuiAppRun[^=]*=(.+)$", line)
                    if p != None:
                        aRun = p.group(1)
               
                    p = re.search("^[^a-zA-Z0-9]*GuiAppIcon[^=]*=(.+)$", line)
                    if p != None:
                        aIcon = p.group(1)

                    p = re.search("^[^a-zA-Z0-9]*GuiAppType[^=]*=(.+)$", line)
                    if p != None:
                        aType = p.group(1)
                    
                    p = re.search("^[^a-zA-Z0-9]*GuiAppDesc[^=]*=(.+)$", line)
                    if p != None:
                        aDesc = p.group(1)

                    p = re.search("^[^a-zA-Z0-9]*GuiAppVersion[^=]*=(.+)$", line)
                    if p != None:
                        aVers = p.group(1)

                    # deprecated, use GuiAppProtocols        
                    p = re.search("^[^a-zA-Z0-9]*GuiAppModes[^=]*=(.+)$", line)
                    if p != None:
                        aModes = p.group(1)

                    p = re.search("^[^a-zA-Z0-9]*GuiAppProtocols[^=]*=(.+)$", line)
                    if p != None:
                        aModes = p.group(1)
                        
                if self.regExpAT.match(line):
                    aDevice = 'a'
                
                if self.regExpB.match(line):
                    aBemused = 1
        
            if (not aName) and (not aType):
               if debug: print 'Not a configuration file. Skip '+cfgFile
               fd.close()
               return
            
            aMode = ['Server']    
            if aModes == '': 
                if aBemused == 1:
                    aMode = ['Bemused']
                elif aDevice == 'a':
                    aMode = ['AT']
            else:
                aMode = [] 
                # not use aModes.split(',') to make more strict control
                if aModes.find('Server') >= 0:
                    aMode.append('Server')

                if aModes.find('Bemused') >= 0:
                    aMode.append('Bemused')
                
                if aModes.find('AT') >= 0:
                    aMode.append('AT')
                
                if aModes.find('iViewer') >= 0:
                    aMode.append('iViewer')
                    
            if aName == '' or aName == None:
                    aName = os.path.basename(cfgFile)
                    
            app = aInst
            isInst = 'OK'
            if aInst != '':
                cnt = aInst.count(' ')
                
                if cnt > 0: # treat this like a command to execute
                    app = getResult(aInst, 'bin')
                
                isInst = isInstalled(app)

            show  = 1
            show1 = 1
            show2 = 1
            status = AR_NOTAVAIL
            if isInst == 'OK':
                status = AR_AVAIL
                
                # check version if requested
                if aVers != '':
                    version = reqVersion(aVers)

                    if version == 'NOK':
                        isInst = 'NOK'
                        status = AR_NOTAVAIL
            
            if isInst == 'NOK' and not cfgReader.showNonavail_:
                show1 = 0
            elif isInst == AR_NOINFO:
                status = ''

            if 'Server' in aMode and not cfgReader.showSrv_:
                aMode.remove('Server')
            
            if 'AT' in aMode and not cfgReader.showAt_:
                aMode.remove('AT')
             
            if 'Bemused' in aMode and not cfgReader.showBm_:
                aMode.remove('Bemused')
        
            if 'iViewer' in aMode and not cfgReader.showIView_:
                aMode.remove('iViewer')
                    
            if len(aMode) > 0:
                show = 1
            else:
                show = 0

            if aType == 'Application' and not cfgReader.showApps_:
                show2 = 0
            elif aType == 'Custom' and not cfgReader.showCustom_:
                show2 = 0
            elif aType == 'Example' and not cfgReader.showExamples_:
                show2 = 0
            elif aType == '':
                show2 = 0
            
            if show == 1 and show1 == 1 and show2 == 1:
                if debug: print 'Proceed '+aName
                                    
                isRun = AR_NOINFO
                if aRun != '':
                    isRun  = getResult(aRun,'reader')
                
                if status == AR_AVAIL and isRun == 'OK':
                    status = AR_RUNNING
                 
                addAppToList(aName, aIcon, app, aRun, isRun, cfgFile, status, aMode, aType, aDesc)
                
                if debug: print 'Processed',cfgFile
            else:
                if debug: print 'Skip',cfgFile
                    
            fd.close()

###############################################################################        
#
# Configuration management
# unified
#
###############################################################################        

class ConfigReader:
    def saveConfig(self):
        
        cfg = os.environ.get("HOME")+os.sep+'.anyRemote'
        if not os.path.exists(cfg):
            os.mkdir(cfg)
            
        f=open(cfg + os.sep + 'anyremote-fe.conf', 'w')
        if f:
            f.write('LastCfgFile='+self.lastCfgFile_+'\n')
            
            what = 'Show='
            if self.showApps_:
                what = what + 'Apps,'
            if self.showCustom_:
                what = what + 'Custom,'
            if self.showExamples_:
                what = what + 'Examples,'
            if self.showNonavail_:
                what = what + 'NonAvail,'
            if self.showAt_:
                what = what + 'AT,'
            if self.showSrv_:
                what = what + 'Server,'
            if self.showBm_:
                what = what + 'Bemused,'
            if self.showIView_:
                what = what + 'IViewer,'
            
            f.write(what+'\n')

            ac = '0'
            if self.autoReconn_:
                ac = '1'
            f.write('AutoReconnectAT='+ac+'\n')
            
            if self.dvSrvBT_ != '':
                f.write('DeviceServerBT='+self.dvSrvBT_+'\n')
            
            if self.dvSrvTCP_ != '':
                f.write('DeviceServerTCP='+self.dvSrvTCP_+'\n')
            
            if self.dvSrvWEB_ != '':
                f.write('DeviceServerWEB='+self.dvSrvWEB_+'\n')
            
            if self.dvSrvADV_ != '':
                f.write('DeviceServerManual='+self.dvSrvADV_+'\n')
             
            useTypes = 'DeviceUseType='
            if self.dvSrvUseADV_:
                useTypes = useTypes + 'ADV'
            else:
                if self.dvSrvUseBT_:
                    useTypes = useTypes + 'BT,'
                if self.dvSrvUseTCP_:
                    useTypes = useTypes + 'TCP,'
                if self.dvSrvUseWEB_:
                    useTypes = useTypes + 'WEB,'
                if self.dvSrvUseAVH_:
                    useTypes = useTypes + 'Avahi,'
            f.write(useTypes+'\n')

            if self.deviceAT_ != '':
                f.write('DeviceAT='+self.deviceAT_+'\n')

            if self.deviceBm_ != '':
                f.write('DeviceBemused='+self.deviceBm_+'\n')

            if self.deviceIV_ != '':
                f.write('DeviceIViewer='+self.deviceIV_+'\n')

            tm = "%s" % (self.updateTmout_)
            f.write('UpdateTimeout='+tm+'\n')
                
            if self.autoStart_ != '':
                f.write('AutoStartFile='+self.autoStart_+'\n')

            if self.doAutoStart_:
                f.write('AutoStart=true\n')
            else:
                f.write('AutoStart=false\n') 

            dirs = 'CfgDirs='
            for d in self.cfgDirs:
                if d != '':
                    dirs = dirs +d + ';'
            f.write(dirs+'\n')
            
            if self.browseTmout_ > 0:
                tm = "%s" % (self.browseTmout_)
                f.write('DeviceBrowserTimeout='+tm+'\n')
            else:
                f.write('DeviceBrowserTimeout=-1\n')
           
            f.write('J2MEDir='+self.j2meDir_+'\n')
            
            if self.checkJ2MEUpdate_:
                f.write('CheckJ2MEUpdate=true\n')
            
            f.close()
            
        saveDevices()

    def setDefaultConfig(self):

        self.lastCfgFile_  = ''
        self.cfgDirs       = []
        self.autoStart_    = ''
        self.doAutoStart_  = False
        self.j2meDir_      = ''
        self.checkJ2MEUpdate_ = False
        self.showApps_     = True
        self.showCustom_   = False
        self.showExamples_ = False
        self.showNonavail_ = False
        self.showAt_       = False
        self.showSrv_      = True
        self.showBm_       = False
        self.showIView_    = False
        self.autoReconn_   = False
        self.dvSrvBT_      = '19'
        self.dvSrvTCP_     = '5197'
        self.dvSrvWEB_     = '5080'
        self.dvSrvADV_     = 'bluetooth:19 -log'
        self.dvSrvUseBT_   = True
        self.dvSrvUseTCP_  = True
        self.dvSrvUseWEB_  = True
        self.dvSrvUseAVH_  = True
        self.dvSrvUseADV_  = False
        self.deviceAT_     = 'rfcomm:'
        self.deviceBm_     = ''
        self.deviceIV_     = 'tcp:5197,web:5198'

        self.updateTmout_  = 60
        self.browseTmout_  = -1
        
    def readConfig(self):
        
        # anyRemote related part
        cfg  = os.environ.get("HOME")+os.sep+'.anyRemote' + os.sep + 'anyremote-fe.conf'
        
        if os.path.exists(cfg):
            f=open(cfg, 'r')
            if f:
                for line in f:
                    line = line.replace('\n','')
 
                    if line.startswith('LastCfgFile='):
                        self.lastCfgFile_=line[12:]
                    elif line.startswith('Show='):
                        #Show=Apps,Custom,Examples
                        what = line[5:].split(',')

                        # override defaults
                        self.showApps_ = False
                        self.showSrv_  = False
                        
                        for item in what:
                            if item == 'Apps':
                                self.showApps_ = True
                            elif item == 'Custom':
                                self.showCustom_ = True
                            elif item == 'Examples':
                                self.showExamples_ = True
                            elif item == 'NonAvail':
                                self.showNonavail_ = True
                            elif item == 'AT':
                                self.showAt_ = True
                            elif item == 'Server':
                                self.showSrv_ = True
                            elif item == 'Bemused':
                                self.showBm_ = True
                            elif item == 'IViewer':
                                self.showIView_ = True
                          
                            # compatibility with old versions
                            elif item == 'All':
                                self.showSrv_      = True
                                self.showApps_     = True
                                self.showCustom_   = True
                                self.showExamples_ = True
                                self.showNonavail_ = True
                              
                    elif line.startswith('AutoReconnectAT='):
                        self.autoReconn_ = (line == 'AutoReconnectAT=1')
                    elif line.startswith('AutoStart='):
                        useM = line[10:]
                        if useM == '1' or useM == 'true' or useM == 'True':
                            self.doAutoStart_ = True
                        else:
                            self.doAutoStart_ = False
                    elif line.startswith('AutoStartFile='):
                        self.autoStart_ = line[14:]
                    elif line.startswith('DeviceServerBT='):
                        self.dvSrvBT_ = line[15:]
                    elif line.startswith('DeviceServerTCP='):
                        self.dvSrvTCP_ = line[16:]
                    elif line.startswith('DeviceServerWEB='):
                        self.dvSrvWEB_ = line[16:]
                    elif line.startswith('DeviceServerManual='):
                        self.dvSrvADV_ = line[19:]
                    elif line.startswith('DeviceUseType='):
                        what = line[14:].split(',')
                        
                        for item in what:
                            if item == 'BT':
                                self.dvSrvUseBT_  = True
                                self.dvSrvUseADV_ = False
                            elif item == 'TCP':
                                self.dvSrvUseTCP_ = True
                                self.dvSrvUseADV_ = False
                            elif item == 'WEB':
                                self.dvSrvUseWEB_ = True
                                self.dvSrvUseADV_ = False
                            elif item == 'Avahi':
                                self.dvSrvUseAVH_ = True
                            elif item == 'ADV':
                                self.dvSrvUseBT_  = False
                                self.dvSrvUseTCP_ = False
                                self.dvSrvUseWEB_ = False
                                self.dvSrvUseAVH_ = False
                                self.dvSrvUseADV_ = True
                            
                    elif line.startswith('DeviceAT='):
                        self.deviceAT_ = line[9:]
                    elif line.startswith('DeviceBemused='):
                        self.deviceBm_ = line[14:]
                    elif line.startswith('DeviceIViewer='):
                        self.deviceIV_ = line[14:]
                    elif line.startswith('CfgDirs='):
                        self.cfgDirs=line[8:].split(';')
                    elif line.startswith('UpdateTimeout='):
                        self.updateTmout_=int(line[14:])
                    elif line.startswith('DeviceBrowserTimeout='):
                        tmt=line[21:]
                        try:
                            self.browseTmout_=int(tmt)
                        except ValueError:
                            self.browseTmout_=-1

                        if self.browseTmout_ <= 0:
                            self.browseTmout_=-1
                    elif line.startswith('J2MEDir='):
                        self.j2meDir_=line[8:]
                    elif line.startswith('CheckJ2MEUpdate=true'):
                        self.checkJ2MEUpdate_=True
                        
                    # compatibility
                    elif line.startswith('JavaDir='):
                        self.j2meDir_=line[8:]
                    # compatibility
                    elif line.startswith('CheckJavaUpdate=true'):
                        self.checkJ2MEUpdate_=True

                f.close()
                
                # Try to search again
                if self.j2meDir_ == '':
                    self.j2meDir_ = getJ2MEPath()
                
        # device browser related part
        cfg  = os.environ.get("HOME")+os.sep+'.anyRemote' + os.sep + AR_FILE_DEVICES
        
        if os.path.exists(cfg) :
            f=open(cfg, 'r')
            if f:
                for line in f:
                    line = line.replace('\n','')
                    os.path.exists(cfg)
                    
                    if line.startswith('Device='):
                        deviceData=line[7:].split(',')
                        
                        # try to be backward compatible
                        if len(deviceData) < 5:
                            print 'Skip peer',deviceData[0],'because of wrong format'
                            continue

                        v1 = deviceData[0]
                        v2 = deviceData[1]
                        v3 = deviceData[2]
                        v4 = deviceData[3]
                        v5 = deviceData[4]
                        
                        addDevice(v1,v2,v3,v4,v5)
                f.close()
                
    def getConnectString(self):
        if self.dvSrvUseADV_:
            return self.dvSrvADV_
        else:
            connStr = ''

            if self.dvSrvUseTCP_ and self.dvSrvTCP_ != '':
                connStr = "tcp:"+self.dvSrvTCP_
            
            sep = ''
            if connStr != '':
                sep = ','

            if self.dvSrvUseBT_ and self.dvSrvBT_ != '':
                connStr = connStr + sep + "bluetooth:"+self.dvSrvBT_

            if connStr != '':
                sep = ','
            
            if self.dvSrvUseWEB_ and self.dvSrvWEB_ != '':
                connStr = connStr + sep +  "web:"+self.dvSrvWEB_

            if connStr != '':
                sep = ','
            
            if self.dvSrvUseAVH_:
                connStr = connStr + sep +  'avahi'
        
            return connStr
        
    def getConnectStatusString(self):
	
	    if cfgReader.showAt_:
                return '';
	    if cfgReader.showBm_:
                return '';
	    if cfgReader.showIView_:

	        temp = cfgReader.deviceIV_;
	        temp = temp.replace('web:',AR_HTTP_PORT+' ');
	        temp = temp.replace('tcp:',AR_TCP_PORT+' ');
	        return temp;

            if self.dvSrvUseADV_:
                return ''
            else:
                connStr = ''

                if self.dvSrvUseTCP_ and self.dvSrvTCP_ != '':
         	    connStr = AR_TCP_PORT+' '+self.dvSrvTCP_

                sep = ''
                if connStr != '':
        	    sep = ', '

                if self.dvSrvUseBT_ and self.dvSrvBT_ != '':
        	    connStr = connStr + sep + AR_BT_PORT+' '+self.dvSrvBT_

                if connStr != '':
        	    sep = ', '

                if self.dvSrvUseWEB_ and self.dvSrvWEB_ != '':
        	    connStr = connStr + sep + AR_HTTP_PORT+' '+self.dvSrvWEB_

                if connStr != '':
        	    sep = ', '

                if self.dvSrvUseAVH_:
        	    connStr = connStr + sep + 'Avahi'

                return connStr

    def setAutoStartFile(self):

        for cfgDir in self.cfgDirs:
        
            if cfgDir == '':
                continue
        
            if os.path.isfile(cfgDir):
                if cfgDir.find('mediacenter.cfg') >= 0:
                    self.autoStart_ = root + os.sep + cfgFile
                    self.doAutoStart_ = True
                    return 
            else:
                for root, dirs, files in os.walk(cfgDir):
                    if 'Utils' in dirs:
                        dirs.remove('Utils')
                    if 'Icons' in dirs:
                        dirs.remove('Icons')
                    if '.svn' in dirs:
                        dirs.remove('.svn')
            
                    for cfgFile in files:
                        nameext = cfgFile.split('.')
                        ext = nameext[len(nameext)-1]
                        
                        if ext == 'png' or ext == 'sh' or ext == 'py' or ext == 'gz':
                            continue
                        
                        if cfgFile == 'mediacenter.cfg':
                            self.autoStart_ = root + os.sep + cfgFile
                            self.doAutoStart_ = True
                            return 

##################################################################################
#
# Application status updater
#
##################################################################################
class StatusUpdater(threading.Thread):

    def __init__(self, timeout):
        threading.Thread.__init__(self) 
        self.tmout = timeout

    def run(self):
        global debug, appData
        
        if debug: print 'StatusUpdater.run',self.tmout
        self.runUpdater = True
        
        while self.runUpdater:
            timer = 0
            
            # catch stop event without waiting full timeout
            while self.runUpdater and timer < self.tmout:
                time.sleep(0.1)
                timer = timer + 0.1
            
            if debug: print 'StatusUpdater: verify'
            
            for k, v in appData.iteritems():
                if not self.runUpdater:
                    break
                        
                aRun = v[3]
                if aRun != '':
                    isRun  = getResult(aRun,'updater')
                            
                    if isRun != v[4]:
                        v[4] = isRun
                        sendMainWindow(20006, [k,v[6],isRun])                

    def stop(self):
        global debug
        if debug: print 'StatusUpdater.stop'
        self.runUpdater = False

##################################################################################
#
# BT communication thread
#
##################################################################################

# Beware:
# Can not run more than one command on BT adapter at once, since it could hungs 

class BtComm(threading.Thread):

    def __init__(self, jDir):
        threading.Thread.__init__(self) 
        self.midletDir = jDir

    def run(self):
        global debug, bt_devices, cmd_array
        
        self.keepRun = True
        
        if debug: print 'BtComm: run'
        
        while self.keepRun:
        
            ctype = ''
            cdata = ''

            try:
                item = cmd_array[0]
                del cmd_array[0] 
                ctype = item[0]
                cdata = item[1]
            except NameError:
                pass
            except TypeError:
                pass
            except IndexError:
                pass

            
            if debug and ctype != '':
                print 'BtComm: (#',len(cmd_array),') got command',ctype,cdata
         
            if ctype == 'scan':
                self.doScan(cdata)
            elif ctype == 'ping':
                self.doPing(cdata)
            elif ctype.startswith('pushjar'):
                self.doPush(cdata,ctype[7:],False)
            elif ctype.startswith('pushjad'):
                self.doPush(cdata,ctype[7:],True)
            elif ctype == 'info':
                self.doInfo(cdata)
            elif ctype == 'test_at':
                self.doAT(cdata)
            else:
                time.sleep(1)
                
    def setStatus(self, address, status):
        global debug, bt_devices, browserWin

        for k, v in bt_devices.iteritems():
 
            if address == v[0]:
                if status != v[5]:
                    v[5] = status
                
                needRun = v[4]  
                if status == AR_AVAIL and needRun != '':
                    if debug: print 'run anyRemote with',needRun
                        
                    startAnyRemote(needRun)
                    
                try:
                    if browserWin != None:
                        sendEvent(browserWin,30000," ") 
                except AttributeError, NameError:
                    pass

                return

    def doScan(self,force):
        global debug
        if debug: print 'BtComm: scan devices'
        existing = getDevSet()
        
        # Search new devices
        nearby_devices = []
        try:
            nearby_devices = bluetooth.discover_devices(lookup_names = True)
        except bluetooth.BluetoothError,msg:
            if debug: print "BtComm: BluetoothError"
            
            # sleep additional 5 sec
            t2 = 0
            while self.keepRun and t2 < 5:
                time.sleep(0.1)
                t2 = t2 + 0.1
        
        if debug: print "BtComm: found %d devices" % len(nearby_devices)

        availSet = getAvailableSet()
        
        for addr,name in nearby_devices:
            if debug: print "  %s - %s" % (addr, name)
        
            channels = ''
            
            services = bluetooth.find_service(address=addr)
            
            for svc in services:
                try:
                    if debug: print addr,svc["name"],svc["port"]
                
                    if svc["name"] == 'Serial Port' or svc["name"].startswith('COM ') or svc["name"].startswith('Dial-up') or svc["name"].startswith('Dialup'):
                        
                        if channels != '':
                            channels = channels+':'
                        channels = channels+str(svc["port"])
                    
                except AttributeError, NameError:
                    pass
            if addr not in existing:
                showDetailsWin([addr, name, name, channels, '', True])
            else:
                if addr in availSet:
                    availSet.remove(addr)
                else:
                    self.setStatus(addr,AR_AVAIL)
            
        for rest in availSet:
            self.setStatus(rest, '')
        
        if debug: print 'BtComm: verify done'
        
        if force == 'T':
            stopPBar()

    def doPing(self, data):
        global debug, detailsWin
        if debug: print 'BtComm: ping device'
        
        sendEvent(detailsWin,31100,'') 
        writePBar(AR_CONN_DEV)
        
        os.system('killall -9 hcitool 2> /dev/null')
        if debug: print 'hcitool name '+data
        ret = getResult('hcitool name '+data,'browser')
        
        stopPBar()
        if (ret == ''):
            sendEvent(detailsWin,31100,_tr('Ping failed !')) 
        else:
            sendEvent(detailsWin,31100,_tr('Ping OK !')) 

    def doPush(self, data, size, usejad):
        global debug
        if debug: print 'BtComm: obex push'

        sendEvent(detailsWin,31100,'') 
        stopPBar()   
        
        dash = '-'
        if size == '':
            dash = ''
        midlet = 'anyRemote' + dash + size + '.jar'
	
        if not os.path.exists(self.midletDir):       
            sendEvent(detailsWin,31100,_tr('Can not find J2ME midlet ('+midlet+_tr(') to upload !')))
            return
        
        path = self.midletDir + os.sep + midlet
        if not os.path.isfile(path):
            sendEvent(detailsWin,31100,_tr('Can not find J2ME midlet ('+midlet+_tr(') to upload !')))
            return
                     
        sender = ''    
        suffix = ' '    
        if (isInstalled('gnome-obex-send') == 'OK'):
            sender = 'gnome-obex-send -d '
        elif (isInstalled('bluetooth-sendto') == 'OK'):
            sender = 'bluetooth-sendto --dest='
        elif (isInstalled('kbtobexclient') == 'OK'):
            sender = 'kbtobexclient'
        elif (isInstalled('bluedevil-sendfile') == 'OK'):
            sender = 'bluedevil-sendfile -u '
            suffix = ' -f '
        elif (isInstalled('blueman-sendto') == 'OK'):
            sender = 'blueman-sendto -d '
        else:
            sendEvent(detailsWin,31100,_tr('None of bluedevil-sendfile, gnome-obex-send, bluetooth-sendto, blueman-sendto and kbtobexclient are installed !'))
            return 
               
        if debug: print sender + data + suffix + path

        ret = getResult(sender + data + suffix + path + ' &','browser')
        
        if usejad:
            jad = 'anyRemote' + dash + size + '.jad'
            path = self.midletDir + os.sep + jad
            if not os.path.isfile(path):
                sendEvent(detailsWin,31100,_tr('Can not find JAD file ('+jad+_tr(') to upload !')))
                return
            
            ret = getResult(sender + data + suffix + path + ' &','browser')
        
    def doInfo(self,data):
        global debug
        if debug: print 'BtComm: get info'

        writePBar('Connecting to device')
        
        services = bluetooth.find_service(address=data)

        if len(services) > 0:
            print "found %d services on %s" % (len(services), data)
            print
        else:
            print "no services found"

        for svc in services:
            print "Service Name: %s"    % svc["name"]
            print "    Host:        %s" % svc["host"]
            print "    Description: %s" % svc["description"]
            print "    Provided By: %s" % svc["provider"]
            print "    Protocol:    %s" % svc["protocol"]
            print "    channel/PSM: %s" % svc["port"]
            print "    svc classes: %s "% svc["service-classes"]
            print "    profiles:    %s "% svc["profiles"]
            print "    service id:  %s "% svc["service-id"]
            print

    def getSerialPort(self,addr):
        services = bluetooth.find_service(address=addr)
        for svc in services:
            try:
                if svc["name"] == 'Serial Port' or svc["name"].startswith('COM ') or svc["name"].startswith('Dial-up') or svc["name"].startswith('Dialup'):
                    return svc["port"]
            except AttributeError, NameError:
                pass
        return None
        
    def send_at(self,sock,cmd):
        global debug
        if len(cmd) == 0: 
            return ''
        
        data = cmd+'\r'
        if debug: print "send",cmd
        
        sock.send(cmd+'\r')
        time.sleep(0.5)
        data = sock.recv(1024)

        if debug: print "got",data
        return data

    def doAT(self,data):
        global debug
        if debug: print 'BtComm: doAT'
            
        sendEvent(detailsWin,31100,'')
        writePBar(AR_CONN_DEV)        
        port = self.getSerialPort(data)
        if debug: print 'BtComm: port',port
        
        if port == None:
            sendEvent(detailsWin,31100,_tr('Can not get port to connect to. Is there any device available ?'))
            pass
        else:
            sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
            try:
                sock.connect((data, port))
            except bluetooth.BluetoothError,msg:
                d = str(msg)
                stopPBar()
                if d.startswith('(111,'):
                    sendEvent(detailsWin,31100,_tr('Connection refused'))
                return

            ret = self.send_at(sock,"ATZ")
            ret = self.send_at(sock,"ATE0")
            ret = self.send_at(sock,"AT+CMER=?")
            
            status = '' 
            if ret.find('ERROR') == -1:
                ret = ret[ret.index('+CMER'):]
                ret = (ret.split('\n'))[0]
            
                AT_CMER=ret.replace(' ','').replace('\r','')
            
                #+CMER: (0,3),(0),(0),(0,1,2),(0)        <- bad
                #+CMER: (0,3),(0,1,2),(0),(0,1,2),(0)        <- OK
                s1 = (AT_CMER.split('('))[2]
                s2 = (s1.split(')'))[0]
                
                status = AT_CMER
                if s2 == '0':
                    status = _tr('AT mode is not supported by phone (')+status+')'
                else:
                    status = _tr('AT mode could be supported by phone (')+status+')'
            else:
                status = _tr('AT mode is not supported by phone (ERROR response)')
                
            sendEvent(detailsWin,31100,status)
            sock.close()

        stopPBar()
   
    def stop(self):
        global debug
        if debug: print 'BtComm stop'
        self.keepRun = False

##################################################################################
#
# Device Browser
#
##################################################################################
class DeviceBrowser(QMainWindow):

    def __init__(self,parent = None,fl = 0):
        global mainWIndow
    
        QMainWindow.__init__(self)
 
        self.setCentralWidget(QWidget(self))
        deviceBrowserLayout = QGridLayout(self.centralWidget())
        deviceBrowserLayout.setMargin(6)
        deviceBrowserLayout.setSpacing(6)

        self.treeview = QTreeWidget(self.centralWidget())
        self.treeview.setColumnCount(4)
        self.treeview.headerItem().setText(0,_tr("Name")+"    ")
        self.treeview.headerItem().setText(0,_tr("Device Name")+"    ")
        self.treeview.headerItem().setText(0,_tr("Address")+"    ")
        self.treeview.headerItem().setText(0,_tr("Status")+"    ")
        
        self.treeview.header().setResizeMode(0,QHeaderView.ResizeToContents)
        self.treeview.header().setResizeMode(1,QHeaderView.ResizeToContents)
        self.treeview.header().setResizeMode(2,QHeaderView.ResizeToContents)
        self.treeview.header().setResizeMode(3,QHeaderView.Stretch)

        deviceBrowserLayout.addWidget(self.treeview,0,0)

        self.scanAction    = QAction(loadIcon("zoom-in",     "filefind"),  _tr("Scan for devices"), self)
        self.detailsAction = QAction(loadIcon("configure",   "configure"), _tr("Details"), self)
        self.deleteAction  = QAction(loadIcon("edit-delete", "editdelete"),_tr('Delete'), self)
        self.closeAction   = QAction(loadIcon("dialog-close","fileclose"), _tr('Close'), self)
        
        self.MenuBar = self.menuBar()

        self.fileMenu = self.MenuBar.addMenu(_tr("File"))
        self.fileMenu.addAction(self.scanAction)
        self.fileMenu.addAction(self.detailsAction)
        self.fileMenu.addAction(self.deleteAction)
        self.fileMenu.addAction(self.closeAction)

        self.languageChange()

        self.resize(QSize(500,250).expandedTo(self.minimumSizeHint()))

        self.connect(self.scanAction,   SIGNAL("triggered()"),self.scan)
        self.connect(self.detailsAction,SIGNAL("triggered()"),self.details)
        self.connect(self.deleteAction, SIGNAL("triggered()"),self.deleteDev)
        self.connect(self.closeAction,  SIGNAL("triggered()"),self.closeAct)

        self.connect(self.treeview,SIGNAL('itemDoubleClicked(QTreeWidgetItem *, int)'), self.listDClicked)
        
        self.treeview.setSelectionMode(QAbstractItemView.SingleSelection)
        self.treeview.sortByColumn(0,Qt.AscendingOrder)
        
        self.populateDeviceList()

    def languageChange(self):
        self.setWindowTitle(_tr("Device Browser"))
        self.treeview.headerItem().setText(0,_tr("Name"))
        self.treeview.headerItem().setText(1,_tr("Device Name"))
        self.treeview.headerItem().setText(2,_tr("Address"))
        self.treeview.headerItem().setText(3,_tr("Status"))
        self.treeview.clear()

        self.scanAction.setText(_tr("Scan for devices"))
        self.detailsAction.setText(_tr("Details"))
        self.deleteAction.setText(_tr('Delete'))
        self.closeAction.setText(_tr('Close'))
        self.fileMenu.menuAction().setText(_tr("File"))
        
        self.detailsWin = None
        self.selected = None

    def populateDeviceList(self):
        global bt_devices
        self.treeview.clear()
        
        for k, v in bt_devices.iteritems():
            lvi = QTreeWidgetItem(self.treeview)
            lvi.setText(0,bt_devices[k][2])       
            lvi.setText(1,bt_devices[k][1])
            lvi.setText(2,bt_devices[k][0])
            lvi.setText(3,bt_devices[k][5])

    def scan(self):
        stopPBar () 
        startPBar(_tr('Scanning'))
        browseDevices('T')

    def details(self):
        global bt_devices
        
        idx = 0
        item = None
        while idx < self.treeview.topLevelItemCount():
            if self.treeview.isItemSelected(self.treeview.topLevelItem(idx)):
                item = self.treeview.topLevelItem(idx)
                break
            idx = idx + 1 

        if item == None:
            return
        try:
            row = bt_devices[str(item.text(2))]
        except KeyError:
            print 'DeviceBrowser.details: KeyError'
            return
            
        showDetailsWin([row[0],row[1],row[2],row[3],row[4],False])

    def listDClicked(self, listItem, column):
        self.details()

    def deleteDev(self):
        global bt_devices
         
        idx = 0
        while idx < self.treeview.topLevelItemCount():
            if self.treeview.isItemSelected(self.treeview.topLevelItem(idx)):
                btAddr = str(self.treeview.takeTopLevelItem(idx).text(2))
                
                if btAddr in bt_devices:
                    del bt_devices[btAddr]
                
                break
            idx = idx + 1 

    def closeEvent(self, event):
        self.closeAct()
        
    def closeAct(self):
        self.hide()
        saveDevices()

    def customEvent(self,event):
        if event.type() == 30000:
            self.populateDeviceList()

##################################################################################
#
# Device Details
#
##################################################################################
class DeviceDetail(QMainWindow):
    def __init__(self, ba, m, n, channels, cfgFile, is_new, jDir):
        global mainWindow

        QMainWindow.__init__(self)
        self.statusBar()

        self.model     = str(m).replace('\n','')
        self.dname     = str(n).replace('\n','')
        self.btAddr    = str(ba)
        self.channels  = channels
        self.cfile     = str(cfgFile)
        self.isNew     = str(is_new)
        self.midletDir = jDir

        self.setCentralWidget(QWidget(self))
        deviceDetailLayout = QGridLayout(self.centralWidget())
        deviceDetailLayout.setMargin(6)
        deviceDetailLayout.setSpacing(6)

        self.deviceName = QLabel(self.centralWidget())
        deviceDetailLayout.addWidget(self.deviceName,0,0)
        
        self.deviceNameValue = QLabel(self.centralWidget())
        deviceDetailLayout.addWidget(self.deviceNameValue,0,1)

        self.btAddress = QLabel(self.centralWidget())
        deviceDetailLayout.addWidget(self.btAddress,0,3,1,2)
        
        self.btAddressValue = QLabel(self.centralWidget())
        deviceDetailLayout.addWidget(self.btAddressValue,0,5,1,2)

        self.specifyName = QLabel(self.centralWidget())
        deviceDetailLayout.addWidget(self.specifyName,1,0)
        
        self.devName = QLineEdit(self.centralWidget())
        deviceDetailLayout.addWidget(self.devName,1,1,1,6)

        self.runWhen = QCheckBox(self.centralWidget())
        self.runWhen.setToolTip(_tr('anyRemote will start only if no other instances of anyRemote are running'))
        deviceDetailLayout.addWidget(self.runWhen,2,0,1,3)
        
        self.fileWhen = QLineEdit(self.centralWidget())
        deviceDetailLayout.addWidget(self.fileWhen,3,0,1,6)
        self.choose = QPushButton(self.centralWidget())
        deviceDetailLayout.addWidget(self.choose,3,6)

        self.kSeparator1 = QFrame(self.centralWidget())
        self.kSeparator1.setFrameShape(QFrame.HLine)
        self.kSeparator1.setFrameShadow(QFrame.Sunken)
        self.kSeparator1.setFrameShape(QFrame.HLine)
        deviceDetailLayout.addWidget(self.kSeparator1,4,0,1,6)

        self.uploadj2me = QPushButton(self.centralWidget())
        deviceDetailLayout.addWidget(self.uploadj2me,5,0)
        
        self.iSet = QLabel(self.centralWidget())
        deviceDetailLayout.addWidget(self.iSet,5,1)
        
        self.buttons = QButtonGroup(self.centralWidget())
        
        self.sz16 = QRadioButton(self.centralWidget())
        deviceDetailLayout.addWidget(self.sz16,5,2)
        self.sz16.setChecked(True)

        self.sz32 = QRadioButton(self.centralWidget())
        deviceDetailLayout.addWidget(self.sz32,5,3)

        self.sz48 = QRadioButton(self.centralWidget())
        deviceDetailLayout.addWidget(self.sz48,5,4)

        self.sz64 = QRadioButton(self.centralWidget())
        deviceDetailLayout.addWidget(self.sz64,5,5)
 
        self.sz128 = QRadioButton(self.centralWidget())
        deviceDetailLayout.addWidget(self.sz128,5,6)

        self.szAll = QRadioButton(self.centralWidget())
        deviceDetailLayout.addWidget(self.szAll,6,2,1,2)
        
        self.buttons.addButton(self.sz16)
        self.buttons.addButton(self.sz32)
        self.buttons.addButton(self.sz48)
        self.buttons.addButton(self.sz64)
        self.buttons.addButton(self.sz128)
        self.buttons.addButton(self.szAll)
        
        self.sz32.setChecked(True)

        self.uplJad = QCheckBox(self.centralWidget())
        self.uplJad.setToolTip(_tr('Can be useful for Samsung phones'))
        deviceDetailLayout.addWidget(self.uplJad,7,0,1,2)

        self.bigTitleIcon = QCheckBox(self.centralWidget())
        self.bigTitleIcon.setToolTip(_tr('16x16 and 64x64 title icons are available'))
        deviceDetailLayout.addWidget(self.bigTitleIcon,7,2,1,4)
        
        self.noJsr82 = QCheckBox(self.centralWidget())
        self.noJsr82.setToolTip(_tr('Can be used on WinMobile devices'))
        deviceDetailLayout.addWidget(self.noJsr82,8,0,1,4)

        self.ping = QPushButton(self.centralWidget())
        deviceDetailLayout.addWidget(self.ping,9,0)
        self.testat = QPushButton(self.centralWidget())
        deviceDetailLayout.addWidget(self.testat,9,1,1,2)

        self.close = QPushButton(self.centralWidget())
        deviceDetailLayout.addWidget(self.close,9,4,1,2)
        self.ok = QPushButton(self.centralWidget())
        deviceDetailLayout.addWidget(self.ok,9,6)

        self.languageChange()
        
        self.connect(self.choose,     SIGNAL("clicked()"),self.chooseAction)
        self.connect(self.ping,       SIGNAL("clicked()"),self.pingAction)
        self.connect(self.testat,     SIGNAL("clicked()"),self.testatAction)
        self.connect(self.uploadj2me, SIGNAL("clicked()"),self.uploadjAction)
        self.connect(self.close,      SIGNAL("clicked()"),self.closeAction)
        self.connect(self.ok,         SIGNAL("clicked()"),self.okAction)
        
        self.connect(self.runWhen,    SIGNAL("toggled(bool)"),self.runWhenChecked)
        
        self.connect(self.szAll,     SIGNAL("toggled(bool)"),self.clicked_szAll)
        self.connect(self.bigTitleIcon, SIGNAL("toggled(bool)"),self.clicked_bti)
        self.connect(self.noJsr82,  SIGNAL("toggled(bool)"),self.clicked_nojsr82)

        self.deviceNameValue.setText(self.model)
        self.btAddressValue.setText(self.btAddr)
        self.devName.setText(self.dname);
        
        if self.cfile == '':
            self.fileWhen.setEnabled(False)
            self.choose.setEnabled(False)
        else:
            self.fileWhen.setEnabled(True)
            self.fileWhen.setText(self.cfile)
            self.runWhen.setChecked(True)
            self.choose.setEnabled(True)
           
        if not os.path.isdir(self.midletDir): 
            self.uploadj2me.setEnabled(False)
            self.uploadj2me.setToolTip(_tr('It needs to install anyremote-j2me-client package first'))

        bt = btVerify()
        if bt == 'NOK': 
            print 'DeviceDetail: Bluetooth not active'
            
            self.ping.setEnabled(False)
            self.ping.setToolTip(_tr('Bluetooth service is not active'))
            self.testat.setEnabled(False)
            self.testat.setToolTip(_tr('Bluetooth service is not active'))
            self.uploadj2me.setEnabled(False)
            self.bigTitleIcon.setEnabled(False)

    def runWhenChecked(self,w):
        if self.runWhen.isChecked():
            self.fileWhen.setEnabled(True)
            self.choose.setEnabled(True)
        else:
            self.fileWhen.setEnabled(False)
            self.fileWhen.setText('')
            self.choose.setEnabled(False)

    def clicked_szAll(self,w):
        if self.szAll.isChecked():
            self.bigTitleIcon.setChecked(False)

    def clicked_bti(self,w):
        if self.szAll.isChecked() and not self.noJsr82.isChecked():
            self.bigTitleIcon.setChecked(False)
                      
        if not self.bigTitleIcon.isChecked():
            self.noJsr82.setChecked(False)

    def clicked_nojsr82(self,w):
        
        self.szAll.setEnabled(not self.noJsr82.isChecked())
        self.sz16.setEnabled (not self.noJsr82.isChecked())
        self.sz32.setEnabled (not self.noJsr82.isChecked())
        self.sz48.setEnabled (not self.noJsr82.isChecked())
        self.sz64.setEnabled (not self.noJsr82.isChecked())

        if self.noJsr82.isChecked():
            self.bigTitleIcon.setChecked(True)
    
    def chooseAction(self):
        global chooserWin
        self.fileWhen.setEnabled(False)
        self.choose.setEnabled(False)
        chooserWin = Chooser(self)
        chooserWin.show()

    def closeEvent(self,arg):
        self.closeAction()

    def closeAction(self):
        self.hide()
    
    def sendReRead(self):
        global browserWin
        sendEvent(browserWin,30000," ") 
    
    def okAction(self):
        global bt_devices

        for k, v in bt_devices.iteritems():
            
            row = bt_devices[k]
            addr = row[0]
            
            if self.btAddr == addr:

                if self.devName.text() != row[2]:
                    row[2] = self.devName.text()
                    
                if self.model != row[1]:
                    row[1] = self.model

                cf = self.fileWhen.text()
                if cf != row[4]:
                    row[4] = cf
                
                self.sendReRead()
                self.hide()
                return

        bt_devices[self.btAddr] = [self.btAddr,self.model,str(self.devName.text()),self.channels,str(self.fileWhen.text()),AR_AVAIL]

        self.sendReRead()
        self.hide()
    
    def testatAction(self):
        global debug
        if debug: print 'Queue test AT'
            
        stopPBar () 
        startPBar(AR_WAIT_OPS)
        queueBT('test_at',self.btAddr)
    
    def uploadjAction(self):
        global debug
        if debug: print 'Queue push request'
        
        sz = '16'
        if self.noJsr82.isChecked():
            sz = 'nojsr82'
        elif self.szAll.isChecked():
            sz = ''
        else:
            if self.sz32.isChecked():
                sz = '32'
            elif self.sz48.isChecked():
                sz = '48'
            elif self.sz64.isChecked():
                sz = '64'
            elif self.sz128.isChecked():
                sz = '128'
               
            if self.bigTitleIcon.isChecked():
                sz = sz+'b'
           
        push = 'pushjar'
        if self.uplJad.isChecked():
            push = 'pushjad'
           
        stopPBar () 
        startPBar(AR_WAIT_OPS)
        queueBT(push+sz,self.btAddr)
    
    def pingAction(self):
        global debug
        if debug: print 'Queue ping request'

        stopPBar () 
        startPBar(_tr('Wait ping results'))
        queueBT('ping',self.btAddr)
        
    def setStatustext(self,text):
        self.statusBar().clearMessage()
        self.statusBar().showMessage(text)

    def customEvent(self,event):
        if event.type() == 31000:
            self.cfile = event.getData()
            self.fileWhen.setText(self.cfile)
            self.fileWhen.setEnabled(True)
            self.choose.setEnabled(True)
        elif event.type() == 32000:
            self.fileWhen.setEnabled(True)
            self.choose.setEnabled(True)
        elif event.type() == 31100:
            self.setStatustext(event.getData())

    def languageChange(self):
        self.setWindowTitle(_tr("Device Parameters"))
        self.deviceNameValue.setText("")
        self.btAddress.setText(_tr("BT address")+': ')
        self.btAddressValue.setText("")
        self.deviceName.setText(_tr("Device Name")+':')
        self.specifyName.setText(_tr("Specify Name")+': ')
        self.iSet.setText(_tr(" with icon set "))
        self.runWhen.setText(_tr("Run anyRemote when discovered"))
        self.bigTitleIcon.setText(_tr("use big title icon"))
        self.noJsr82.setText(_tr("use version without JSR-82"))
        self.uplJad.setText(_tr("Also upload JAD"))
        self.sz16.setText("16x16")
        self.sz32.setText("32x32")
        self.sz48.setText("48x48")
        self.sz64.setText("64x64")
        self.sz128.setText("128x128")
        self.szAll.setText(_tr("with all icon sets"))
        self.choose.setText(_tr('Choose'))
        self.ping.setText(_tr("Ping"))
        self.uploadj2me.setText(_tr("Upload J2ME"))
        self.testat.setText(_tr("Test AT"))
        self.close.setText(_tr('Close'))
        self.ok.setText(_tr('OK'))

##################################################################################
#
# Configuration checker
#
##################################################################################
class CfgChecker(QMainWindow):

    def __init__(self,parent = None,fl = 0):
    
        global cfgReader
        
        QMainWindow.__init__(self)

        self.setCentralWidget(QWidget(self))
        cfgCheckerLayout = QGridLayout(self.centralWidget())
        cfgCheckerLayout.setMargin(6)
        cfgCheckerLayout.setSpacing(6)

        self.treeview = QTreeWidget(self.centralWidget())
        self.treeview.setColumnCount(2)
        self.treeview.headerItem().setText(0,_tr("Package")+"    ")
        self.treeview.headerItem().setText(1,_tr("Status")+"         ")
        
        self.treeview.header().setResizeMode(0,QHeaderView.ResizeToContents)
        self.treeview.header().setResizeMode(1,QHeaderView.Stretch)

        cfgCheckerLayout.addWidget(self.treeview,0,0)

        self.closeAction   = QAction(loadIcon("dialog-close","fileclose"), _tr("Close"), self)

        self.MenuBar = self.menuBar()

        self.fileMenu = self.MenuBar.addMenu(_tr("File"))
        self.fileMenu.addAction(self.closeAction)
 
        self.languageChange()

        self.resize(QSize(450,250).expandedTo(self.minimumSizeHint()))

        self.connect(self.closeAction,  SIGNAL("triggered()"),self.closeAct)
        
        self.treeview.setSelectionMode(QAbstractItemView.SingleSelection)
        self.treeview.setSortingEnabled(True)
        self.treeview.sortByColumn(0,Qt.DescendingOrder)
        self.treeview.setRootIsDecorated(False)
        
        pbs = AR_NOTINSTALLED
        if pybluez: pbs = AR_INSTALLED
        
        ars = isInstalled('anyremote')
        if ars == 'NOK':
            ars = AR_NOTINSTALLED
        else:
            ars = AR_INSTALLED

        bus = isInstalled('sdptool')
        if bus == 'NOK':
            bus = AR_NOTINSTALLED
        else:
            bus = AR_INSTALLED

        jDir = getJ2MEPath()
        jVer = ''
        ajs = AR_INSTALLED
        if jDir == '':
            ajs = AR_NOTINSTALLED
        else:
            jVer = getJ2MEClientVersion(jDir+os.sep+'anyRemote-16.jad')
            
        if jDir == os.environ.get("HOME")+os.sep+'.anyRemote':
            ajs = _tr('Downloaded')
        
        ajs = ajs+' v.'+jVer

        bts = btVerify()
        if bts == 'NOK':
            bts = _tr('Not active')
        else:
            bts = _tr('Active')
    
        lvi = QTreeWidgetItem(self.treeview)
        lvi.setText(0,"anyRemote")       
        lvi.setText(1,ars)
        
        lvi = QTreeWidgetItem(self.treeview)
        lvi.setText(0,"Bluez utilities")       
        lvi.setText(1,bus)

        lvi = QTreeWidgetItem(self.treeview)
        lvi.setText(0,"PyBluez")       
        lvi.setText(1,pbs)

        lvi = QTreeWidgetItem(self.treeview)
        lvi.setText(0,"anyremote-j2me-client")       
        lvi.setText(1,ajs)

        if jDir != cfgReader.j2meDir_:
            lvi.setExpanded(True)
            lvi2 = QTreeWidgetItem(lvi)
            lvi2.setText(0,_tr('Warning:'))       
            lvi2.setText(1,_tr('Installation directory of anyremote-j2me-client not specified in current setup configuration !'))

        lvi = QTreeWidgetItem(self.treeview)
        lvi.setText(0,"Bluetooth service")       
        lvi.setText(1,bts)
 
    def languageChange(self):
        self.setWindowTitle(_tr("Configuration Check"))
        self.treeview.headerItem().setText(0,_tr("Package")+"    ")
        self.treeview.headerItem().setText(1,_tr("Status")+"         ")
        self.treeview.clear()
        item = QTreeWidgetItem(self.treeview,None)

        self.closeAction.setText(_tr('Close'))
        self.fileMenu.menuAction().setText(_tr("File"))
        
        self.cfgChkWin = None
        self.selected = None

    def closeEvent(self, event):
        self.closeAct()

    def closeAct(self):
        self.hide()

##################################################################################
#
# Choose app. to manage when phone is discovered
#
##################################################################################

class Chooser(QMainWindow):

    def __init__(self,parent = None,fl = 0):
        QMainWindow.__init__(self)
        
        self.parent = parent
        
        self.setCentralWidget(QWidget(self))
        chooserLayout = QGridLayout(self.centralWidget())
        chooserLayout.setMargin(6)
        chooserLayout.setSpacing(6)

        self.listView1 = QTreeWidget(self.centralWidget())
        
        self.listView1.setColumnCount(3)
        self.listView1.headerItem().setText(0,_tr("Application")+"    ")
        self.listView1.headerItem().setText(1,_tr("Mode")+"    ")
        self.listView1.headerItem().setText(2,_tr("F")+"    ")

        self.listView1.header().setResizeMode(0,QHeaderView.ResizeToContents)
        self.listView1.header().setResizeMode(1,QHeaderView.Stretch)
        
        self.listView1.setSelectionMode(QAbstractItemView.SingleSelection)
        self.listView1.hideColumn(2)
        self.listView1.sortByColumn(0,Qt.AscendingOrder)
        
        self.connect(self.listView1,SIGNAL('itemDoubleClicked(QTreeWidgetItem *, int)'), self.listDClicked)
        
        chooserLayout.addWidget(self.listView1,0,0,1,2)

        self.ok = QPushButton(self.centralWidget())
        chooserLayout.addWidget(self.ok,1,0)
        
        self.cancel = QPushButton(self.centralWidget())
        chooserLayout.addWidget(self.cancel,1,1)


        self.languageChange()

        self.resize(QSize(350,400).expandedTo(self.minimumSizeHint()))

        self.connect(self.cancel, SIGNAL("clicked()"),self.cancelAction)
        self.connect(self.ok,     SIGNAL("clicked()"),self.okAction)
        
        self.populateChooseList()
    
    def populateChooseList(self):
        global appData
        
        for k, v in appData.iteritems():
            lvi = QTreeWidgetItem(self.listView1)
            
            ic = loadAppIcon(v[1])
            lvi.setIcon(0,ic)
            lvi.setText(0,v[0])          
            lvi.setText(1,v[7])
            lvi.setText(2,str(k))
                    
    def listDClicked(self, listItem, column):
        self.okAction()

    def cancelAction(self):
        sendEvent(self.parent,32000,'') 
        self.hide()

    def okAction(self):
        global appData

        idx  = 0
        item = None
        while idx < self.listView1.topLevelItemCount():
            item = self.listView1.topLevelItem(idx)
            if self.listView1.isItemSelected(self.listView1.topLevelItem(idx)):
                item = self.listView1.topLevelItem(idx)
                break
            idx = idx + 1

        if item == None:
            return

        try:
            idx = int(str(item.text(2)))
        except ValueError:
            return
        try:
            row = appData[idx]
        except KeyError:
            return
        
        sendEvent(self.parent,31000,appData[idx][5]) 
        self.hide()
   
    def closeEvent(self, event):
        self.cancelAction()

    def languageChange(self):
        self.setWindowTitle(_tr("Choose application"))
        self.listView1.headerItem().setText(0,_tr("Application"))
        self.listView1.headerItem().setText(1,_tr("Mode"))
        self.listView1.clear()
        item = QTreeWidgetItem(self.listView1,None)

        self.cancel.setText(_tr('Close'))
        self.ok.setText(_tr('OK'))


##################################################################################
#
# Progress bar window
#
##################################################################################
class PBar(QProgressDialog):
    def __init__(self, text, steps):
        QProgressDialog.__init__(self, text, '', 0,steps)
        
        bar = QProgressBar(self)
        bar.setTextVisible(False)
        self.setBar(bar)
        self.setMinimum(0)
        self.setMaximum(10)
        self.setCancelButton(None)
        self.setAutoReset(True)
        self.setAutoClose(False)
        self.show()

def sendMainWindow(code,text):
    global mainWindow
    if mainWindow:
        sendEvent(mainWindow, code, text)        

def startPBar(text):
    sendMainWindow(20019, text)        

def stopPBar():
    sendMainWindow(20018, '')        
        
def writePBar(text):
    sendMainWindow(20021, text)        
        
def timerPBar():
    global pbar, pbarTimer, quitFlag

    if not quitFlag:
            try:
                pbar.setValue(pbar.value()+1)
            except AttributeError, NameError:
                return
            pbarTimer = QTimer.singleShot(200,timerPBar)
      
##################################################################################
#
# Frontend to anyRemote
#
##################################################################################

class FrontEnd(threading.Thread):
    def __init__(self):
        global debug
        threading.Thread.__init__(self)        
        self.isReady = False
        if debug: print 'FrontEnd init'

    def ready(self):
        return self.isReady

    def stop(self):
        global debug
        if debug: print 'FrontEnd stop'
        self.isRun = False

    def run(self):
        global port, cmdToSend, debug
        if debug: print 'FrontEnd thread is running', port

        self.isRun = True
        s = None
        for res in socket.getaddrinfo('localhost', port, socket.AF_INET, socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
            af, socktype, proto, canonname, sa = res

            try:
                s = socket.socket(af, socktype, proto)
                s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
                s.setblocking(0)
            except socket.error, msg:
                s = None
                continue
            if debug: print 'FrontEnd socket created'
                    
            try:
                s.bind(sa)
                s.listen(1)
            except socket.error, msg:
                s.close()
                s = None
                continue
            if debug: print 'FrontEnd socket after listen'
            break
                
        if s is None:
            if debug: print 'FrontEnd could not open socket'
            sys.exit(1)

        while self.isRun:
            while self.isRun:

                self.isReady = True
                try:
                    conn, addr = s.accept()
                    if debug: print 'accept', addr
                    break
                except socket.error,msg:
                    time.sleep(0.1)

            if self.isRun:
                self.processOneConnection(conn, addr)

        if debug: print 'Close server socket' 
        s.close()

    def processOneConnection(self,conn,addr):
        global cmdToSend, debug

        if debug: print 'FrontEnd processOneConnection', addr

        self.isConn = True
        while self.isRun and self.isConn:

            conn.setblocking(0)

            if debug: print 'FrontEnd.Connected by', addr

            sendMainWindow(20003,'')

            while self.isRun and self.isConn:

                time.sleep(0.2)

                data = ''
                try:
                    data = conn.recv(512)
                    if debug: print 'Got from backend ', data
                        
                    if self.isRun:
                        sendMainWindow(10000,data)

                    if not data: 
                        if debug: print 'FrontEnd anyRemote die?'

                        if self.isRun:
                            sendMainWindow(20000,'') 
                            self.isConn = False
                        break

                except socket.error,msg:
                    pass

                try:
                    if cmdToSend:
                        if debug: print 'Send to backend '+cmdToSend + "\n"
                        conn.sendall(cmdToSend)
                        cmdToSend = '';
                except socket.error, NameError:
                    if debug: print 'FrontEnd.processOneConnection exception'
                    pass

            if debug: print 'Close connection' 
            sendMainWindow(20012,'')  
            conn.close()

##################################################################################
#
# Edit window
#
##################################################################################

class EditWin(QMainWindow):
    def __init__(self,efile,parent = None,fl = 0):
        QMainWindow.__init__(self)
        
        self.eFile    = efile

        self.setCentralWidget(QWidget(self))
        editWinLayout = QGridLayout(self.centralWidget())
        editWinLayout.setMargin(6)
        editWinLayout.setSpacing(6)
 
        self.textEdit1 = QTextEdit(self.centralWidget())

        editWinLayout.addWidget(self.textEdit1,0,0)

        self.saveEditor   = QAction(loadIcon("document-save",   "filesave"),  _tr("Save"),   self)
        self.saveAsEditor = QAction(loadIcon("document-save-as","filesaveas"),_tr("Save As"),self)
        self.closeEditor  = QAction(loadIcon("dialog-close",    "fileclose"), _tr("Close"),  self)
        
        self.Menu = self.menuBar()
        
        self.fileMenu = self.Menu.addMenu(_tr("File"))
        self.fileMenu.addAction(self.saveEditor)
        self.fileMenu.addAction(self.saveAsEditor)
        self.fileMenu.addAction(self.closeEditor)

        self.languageChange()

        self.resize(QSize(550,600).expandedTo(self.minimumSizeHint()))
        #self.clearWState(Qt.WState_Polished)
        
        self.connect (self.saveEditor,  SIGNAL ("triggered()"), self.saveFile)
        self.connect (self.saveAsEditor,SIGNAL ("triggered()"), self.saveAs)
        self.connect (self.closeEditor, SIGNAL ("triggered()"), self.cancel_clicked)
        
        self.loadEditFile()
        
    def loadEditFile(self):
    
        infile = None
        
        writable = False
        try:
            infile = open(self.eFile, "r")
            writable = QFileInfo(self.eFile).isWritable()
        except IOError:
            pass
            
        if infile:
            string = infile.read()
            infile.close()
            self.textEdit1.setText(string)
            self.textEdit1.setReadOnly(not writable)
        else:
            self.eFile = ""

    def languageChange(self):
        self.setWindowTitle(_tr("Edit configuration file"))
        self.closeEditor.setText(_tr("Close"))
        self.saveEditor.setText(_tr("Save"))
        self.saveEditor.setShortcut(QKeySequence(_tr("Ctrl+S")))
        self.saveAsEditor.setText(_tr("Save As"))
        self.fileMenu.menuAction().setText(_tr("File"))


    def saveFile(self):
        try:
            f=open(self.eFile, 'w')
            if f:
                #text = self.textEdit1.text() not work ?
                text = self.textEdit1.document().toPlainText()
                f.write(str(text))
                f.close()
                self.deleteLater()   

        except IOError:
            sendMainWindow(20016, _tr("Can not save the file !"))
            self.saveAs()
 
    def saveAs(self):
        f = QFileDialog.getSaveFileName(None,"", "");
        if f:
            self.eFile = f
            self.saveFile()
        
    def cancel_clicked(self):
        self.deleteLater()   

    def closeEvent(self, event):
        self.cancel_clicked()
        
##################################################################################
#
# Preferences window
#
##################################################################################

class Preferences(QMainWindow):
    def __init__(self):
        
        global cfgReader
        
        QMainWindow.__init__(self)
 
        self.setMinimumSize(QSize(670,300))

        self.setCentralWidget(QWidget(self))
        prefsLayout = QGridLayout(self.centralWidget())
        prefsLayout.setMargin(6)
        prefsLayout.setSpacing(6)
        
        self.tabs = QTabWidget(self.centralWidget())
        prefsLayout.addWidget(self.tabs,0,0,5,5)

        #############################
        ### Common tab
        #############################
        commonFrame = QFrame()
        self.tabs.addTab(commonFrame,_tr("General"))
        PreferencesCommonLayout = QGridLayout(commonFrame)

        self.autoRun = QCheckBox(commonFrame)
        PreferencesCommonLayout.addWidget(self.autoRun,0,0,1,2)
        self.autoFile = QLineEdit(commonFrame)
        PreferencesCommonLayout.addWidget(self.autoFile,0,2,1,8)
        self.chooseAuto = QPushButton(commonFrame)
        PreferencesCommonLayout.addWidget(self.chooseAuto,0,10,1,2)

        self.dirView = QTreeWidget(commonFrame)
        self.dirView.setColumnCount(1)
        self.dirView.headerItem().setText(0,_tr("Directories"))
        self.dirView.setMinimumHeight(60)
        self.dirView.setMaximumHeight(90)
        self.dirView.setToolTip(_tr("Choose directories with configuration files and add them to the list"))
        PreferencesCommonLayout.addWidget(self.dirView,1,0,1,12)

        self.addButton = QPushButton(commonFrame)
        PreferencesCommonLayout.addWidget(self.addButton,2,0,1,2)
        self.delButton = QPushButton(commonFrame)
        PreferencesCommonLayout.addWidget(self.delButton,2,2,1,2)

        ###
        self.line10 = QFrame(commonFrame)
        self.line10.setFrameShape(QFrame.HLine)
        self.line10.setFrameShadow(QFrame.Sunken)
        self.line10.setFrameShape(QFrame.HLine)
        PreferencesCommonLayout.addWidget(self.line10,3,0,1,12)

        ###
        self.showInList = QLabel(commonFrame)
        PreferencesCommonLayout.addWidget(self.showInList,4,0,1,3)
        self.at = QRadioButton(commonFrame)
        PreferencesCommonLayout.addWidget(self.at,4,3,1,2)
        self.srv = QRadioButton(commonFrame)
        PreferencesCommonLayout.addWidget(self.srv,4,5,1,2)
        self.bem = QRadioButton(commonFrame)
        PreferencesCommonLayout.addWidget(self.bem,4,7,1,2)
        self.iv = QRadioButton(commonFrame)
        PreferencesCommonLayout.addWidget(self.iv,4,9,1,2)
       
        ###
        self.appl = QCheckBox(commonFrame)
        PreferencesCommonLayout.addWidget(self.appl,5,3,1,2)
        self.custom = QCheckBox(commonFrame)
        PreferencesCommonLayout.addWidget(self.custom,5,5,1,2)
        self.examples = QCheckBox(commonFrame)
        PreferencesCommonLayout.addWidget(self.examples,5,7,1,2)
        self.nonAv = QCheckBox(commonFrame)
        PreferencesCommonLayout.addWidget(self.nonAv,5,9,1,2)
        
        ###
        self.line12 = QFrame(commonFrame)
        self.line12.setFrameShape(QFrame.HLine)
        self.line12.setFrameShadow(QFrame.Sunken)
        self.line12.setFrameShape(QFrame.HLine)
        PreferencesCommonLayout.addWidget(self.line12,6,0,1,12)
        
        ###
        self.autoStart = QLabel(commonFrame)
        PreferencesCommonLayout.addWidget(self.autoStart,7,0,1,4)
        self.autoGnome = QCheckBox(commonFrame)
        PreferencesCommonLayout.addWidget(self.autoGnome,7,4,1,4)
        self.autoKDE = QCheckBox(commonFrame)
        PreferencesCommonLayout.addWidget(self.autoKDE,7,8,1,4)

        ###
        self.line15 = QFrame(commonFrame)
        self.line15.setFrameShape(QFrame.HLine)
        self.line15.setFrameShadow(QFrame.Sunken)
        self.line15.setFrameShape(QFrame.HLine)
        PreferencesCommonLayout.addWidget(self.line15,8,0,1,12)
                        
        ###
        self.updateAppList = QLabel(commonFrame)
        PreferencesCommonLayout.addWidget(self.updateAppList,9,0,1,4)
        self.tmout = QLineEdit(commonFrame)
        self.tmout.setToolTip(_tr('Empty field means no update'))
        PreferencesCommonLayout.addWidget(self.tmout,9,4)
        self.secLabel1 = QLabel(commonFrame)
        PreferencesCommonLayout.addWidget(self.secLabel1,9,5)
        
        self.labelRunWhen = QLabel(commonFrame)
        PreferencesCommonLayout.addWidget(self.labelRunWhen,9,6,1,4,Qt.AlignRight)
        self.browseTmout = QLineEdit(commonFrame)
        self.browseTmout.setToolTip(_tr('Empty field means no update. Beware: Android/J2ME clients could fail to connect to anyRemote when browsing is in process'))
        PreferencesCommonLayout.addWidget(self.browseTmout,9,10)

        self.secLabel2 = QLabel(commonFrame)
        PreferencesCommonLayout.addWidget(self.secLabel2,9,11)

        #############################
        ### Server mode tab        
        #############################
        srvFrame = QFrame()
        self.tabs.addTab(srvFrame,_tr("Server Mode"))
        PreferencesSrvLayout = QGridLayout(srvFrame)
        
        self.connBT = QCheckBox(srvFrame)
        PreferencesSrvLayout.addWidget(self.connBT,0,0,1,3)
        self.dataBT = QLineEdit(srvFrame)
        PreferencesSrvLayout.addWidget(self.dataBT,0,3,1,4)
        
        self.connTCP = QCheckBox(srvFrame)
        PreferencesSrvLayout.addWidget(self.connTCP,1,0,1,3)
        self.dataTCP = QLineEdit(srvFrame)
        PreferencesSrvLayout.addWidget(self.dataTCP,1,3,1,4)
        
        self.connWEB = QCheckBox(srvFrame)
        PreferencesSrvLayout.addWidget(self.connWEB,2,0,1,3)
        self.dataWEB = QLineEdit(srvFrame)
        PreferencesSrvLayout.addWidget(self.dataWEB,2,3,1,4)

        self.connAVH = QCheckBox(srvFrame)
        PreferencesSrvLayout.addWidget(self.connAVH,3,0,1,3)
        
        self.connMAN = QCheckBox(srvFrame)
        PreferencesSrvLayout.addWidget(self.connMAN,4,0,1,3)
        self.dataMAN = QLineEdit(srvFrame)
        PreferencesSrvLayout.addWidget(self.dataMAN,4,3,1,4)
         
        ###
        self.line11 = QFrame(srvFrame)
        self.line11.setFrameShape(QFrame.HLine)
        self.line11.setFrameShadow(QFrame.Sunken)
        self.line11.setFrameShape(QFrame.HLine)
        PreferencesSrvLayout.addWidget(self.line11,5,0,1,7)

        ###
        self.jdirLabel = QLabel(srvFrame)
        PreferencesSrvLayout.addWidget(self.jdirLabel,6,0,1,2)
        self.j2meDir = QLineEdit(srvFrame)
        PreferencesSrvLayout.addWidget(self.j2meDir,6,2,1,4)
        self.jDir = QPushButton(srvFrame)
        PreferencesSrvLayout.addWidget(self.jDir,6,6)

        ###
        self.checkJ2ME = QCheckBox(srvFrame)
        PreferencesSrvLayout.addWidget(self.checkJ2ME,7,0,1,6)

        self.checkJ2MENow = QPushButton(srvFrame)
        PreferencesSrvLayout.addWidget(self.checkJ2MENow,7,5,1,2)
        
        self.downloadJ2MENow  = QPushButton(srvFrame)
        self.downloadJ2MENow.setToolTip(_tr('Files will be saved to $HOME/.anyRemote'))
        PreferencesSrvLayout.addWidget(self.downloadJ2MENow,8,5,1,2)
                
        self.empty = QLabel(srvFrame)
        self.empty.setText('')
        PreferencesSrvLayout.addWidget(self.empty,10,0)
        
        #############################
        ### AT mode tab        
        #############################
        atFrame = QFrame()
        self.tabs.addTab(atFrame,_tr("AT mode"))
        PreferencesATLayout = QGridLayout(atFrame)
        
        ###
        self.deviceATL = QLabel(atFrame)
        PreferencesATLayout.addWidget(self.deviceATL,0,0,1,2)
        self.deviceAT = QComboBox(atFrame)
        PreferencesATLayout.addWidget(self.deviceAT,0,2)

        ###
        self.auto_reconnect = QCheckBox(atFrame)
        PreferencesATLayout.addWidget(self.auto_reconnect,2,0,1,6)
                
        self.empty = QLabel(atFrame)
        self.empty.setText('')
        PreferencesATLayout.addWidget(self.empty,10,0)

        #############################
        ### Bemused tab        
        #############################
        bmFrame = QFrame()
        self.tabs.addTab(bmFrame,_tr("Bemused"))
        PreferencesBmLayout = QGridLayout(bmFrame)
        
        ###
        self.deviceBmL = QLabel(bmFrame)
        PreferencesBmLayout.addWidget(self.deviceBmL,0,0,1,2)
        self.deviceBm = QLineEdit(bmFrame)
        PreferencesBmLayout.addWidget(self.deviceBm,0,2)
        
        self.empty = QLabel(bmFrame)
        self.empty.setText('')
        PreferencesBmLayout.addWidget(self.empty,10,0)

        #############################
        ### iViewer tab        
        #############################
        ivFrame = QFrame()
        self.tabs.addTab(ivFrame,_tr("iViewer"))
        PreferencesIVLayout = QGridLayout(ivFrame)

        ###
        self.deviceIVL = QLabel(ivFrame)
        PreferencesIVLayout.addWidget(self.deviceIVL,0,0)
        self.deviceIV = QLineEdit(ivFrame)
        PreferencesIVLayout.addWidget(self.deviceIV,0,1,1,5)
         
        self.empty = QLabel(ivFrame)
        self.empty.setText('')
        PreferencesIVLayout.addWidget(self.empty,10,0)

        #############################
        self.cancel = QPushButton(self.centralWidget())
        prefsLayout.addWidget(self.cancel,6,3)
        self.ok = QPushButton(self.centralWidget())
        prefsLayout.addWidget(self.ok,6,4)

        self.languageChange()

        self.resize(QSize(500,300).expandedTo(self.minimumSizeHint()))
        #self.clearWState(Qt.WState_Polished)

        self.connect(self.delButton,SIGNAL("clicked()"),self.delete_clicked)
        self.connect(self.addButton,SIGNAL("clicked()"),self.add_clicked)
        self.connect(self.jDir,     SIGNAL("clicked()"),self.chooseJ2MEDir)
        self.connect(self.cancel,   SIGNAL("clicked()"),self.cancel_clicked)
        self.connect(self.ok,       SIGNAL("clicked()"),self.ok_clicked)
        
        self.connect(self.checkJ2MENow, SIGNAL("clicked()"),   self.checkJ2MEWeb)
        self.connect(self.downloadJ2MENow, SIGNAL("clicked()"),self.uploadJ2MEWeb)
        
        self.connect(self.nonAv,    SIGNAL("toggled(bool)"),self.filterChangedAction)
        self.connect(self.appl,     SIGNAL("toggled(bool)"),self.filterChangedAction)
        self.connect(self.custom,   SIGNAL("toggled(bool)"),self.filterChangedAction)
        self.connect(self.examples, SIGNAL("toggled(bool)"),self.filterChangedAction)
        self.connect(self.at,       SIGNAL("toggled(bool)"),self.filterChangedAction)
        self.connect(self.srv,      SIGNAL("toggled(bool)"),self.filterChangedAction)
        self.connect(self.bem,      SIGNAL("toggled(bool)"),self.filterChangedAction)
        self.connect(self.iv,       SIGNAL("toggled(bool)"),self.filterChangedAction)
       
        self.connect(self.autoRun,  SIGNAL("toggled(bool)"),self.autoRunToggled)
        self.connect(self.chooseAuto, SIGNAL("clicked()"),self.chooseAutoStart)
        
        self.connect(self.connBT,    SIGNAL("toggled(bool)"),self.btToggled)
        self.connect(self.connTCP,   SIGNAL("toggled(bool)"),self.tcpToggled)
        self.connect(self.connWEB,   SIGNAL("toggled(bool)"),self.webToggled)
        self.connect(self.connAVH,   SIGNAL("toggled(bool)"),self.avhToggled)
        self.connect(self.connMAN,   SIGNAL("toggled(bool)"),self.manToggled)
        
        self.connect(self.dataBT, SIGNAL("textChanged(const QString&)"),self.btChangedAction)
        self.connect(self.dataTCP,SIGNAL("textChanged(const QString&)"),self.tcpChangedAction)
        self.connect(self.dataWEB,SIGNAL("textChanged(const QString&)"),self.webChangedAction)
        self.connect(self.dataMAN,SIGNAL("textChanged(const QString&)"),self.manChangedAction)
        
        self.connect(self.deviceBm, SIGNAL("textChanged(const QString&)"),self.deviceBmChangedAction)
        self.connect(self.deviceIV, SIGNAL("textChanged(const QString&)"),self.deviceIVChangedAction)

        self.connect(self.tmout,       SIGNAL("textChanged(const QString&)"),self.updateAppChangedAction)
        self.connect(self.browseTmout, SIGNAL("textChanged(const QString&)"),self.browseDevChangedAction)
        
        self.updateAppChangedAction('')
        self.browseDevChangedAction('')

        self.makeGuiSetup()
        
    def makeGuiSetup(self):
        global bt_devices, cfgReader
        
        self.autoRun.setChecked (cfgReader.doAutoStart_)
        self.autoFile.setText   (cfgReader.autoStart_)

        self.appl.setChecked    (cfgReader.showApps_)
        self.custom.setChecked  (cfgReader.showCustom_)
        self.examples.setChecked(cfgReader.showExamples_)
        self.nonAv.setChecked   (cfgReader.showNonavail_)
        
        self.at.setChecked      (cfgReader.showAt_)
        self.srv.setChecked     (cfgReader.showSrv_)
        self.bem.setChecked     (cfgReader.showBm_)
        self.iv.setChecked      (cfgReader.showIView_)

        self.connBT.setChecked  (cfgReader.dvSrvUseBT_)
        self.connTCP.setChecked (cfgReader.dvSrvUseTCP_)
        self.connWEB.setChecked (cfgReader.dvSrvUseWEB_)
        self.connAVH.setChecked (cfgReader.dvSrvUseAVH_)
        self.connMAN.setChecked (cfgReader.dvSrvUseADV_)
            
        self.dataBT.setText (cfgReader.dvSrvBT_)
        self.dataTCP.setText(cfgReader.dvSrvTCP_)
        self.dataWEB.setText(cfgReader.dvSrvWEB_)
        self.dataMAN.setText(cfgReader.dvSrvADV_)
        
        self.setSensitivity()
        
        tm = ''
        if cfgReader.updateTmout_ > 0:
            tm = "%s" % (cfgReader.updateTmout_)
        self.tmout.setText(tm)

        tm = ''
        if cfgReader.browseTmout_ > 0:
            tm = "%s" % (cfgReader.browseTmout_)
        self.browseTmout.setText(tm)
        
        self.autoGnome.setChecked(os.path.exists(os.environ.get("HOME")+os.sep+'.config'+os.sep+'autostart'+os.sep+'kanyremote.desktop'))
        self.autoKDE.setChecked(os.path.exists(os.environ.get("HOME")+os.sep+'.kde'+os.sep+'Autostart'+os.sep+'kanyremote'))        
        
        self.auto_reconnect.setChecked(cfgReader.autoReconn_)
        
        if cfgReader.deviceAT_ != "":
            self.deviceAT.addItem(cfgReader.deviceAT_)
            self.deviceAT.setCurrentIndex(0)
            
        for k, v in bt_devices.iteritems():

            row = bt_devices[k]
            v1 = row[0]
            v4 = row[3]
            
            # use channel 1 as default
            if v4 == "":
                v4 = "1"
            
            channels = v4.split(':')
            for ch in channels:
                if str(ch).isdigit():
                    crow = "rfcomm:"+v1+":"+ch
                    if cfgReader.deviceAT_ != crow:
                        self.deviceAT.addItem(crow)
        
        self.deviceBm.setText(cfgReader.deviceBm_)
        self.deviceIV.setText(cfgReader.deviceIV_)
        
        self.j2meDir.setText(cfgReader.j2meDir_)
        
        self.checkJ2ME.setChecked(cfgReader.checkJ2MEUpdate_)
        
        self.dirView.clear()
        for d in cfgReader.cfgDirs:
            if d != '':
                lvi = QTreeWidgetItem(self.dirView)
                lvi.setText(0,d)
        
        self.addDir      = ''
        self.dirsChanged = False
        
        self.deviceIVChangedAction(self)
        
    def uploadJ2MEWeb(self):
        global debug, jup, cfgReader
        
        try:
            if jup != None:
                if debug: print 'Uploading already active. Skip request.'
                return
        except NameError:
            pass

        jup = JCUploader()
        jup.start()
        
        cfgReader.j2meDir_ = os.environ.get("HOME")+os.sep+'.anyRemote'
        try:
            self.j2meDir.setText(cfgReader.j2meDir_)
        except AttributeError:
            # OK. config window was not yet shown
            pass
                    
    def checkJ2MEWeb(self):
        jv = JCVerifier(True)
        jv.start()

    def closeEvent(self, event):
        self.cancel_clicked()

    def languageChange(self):
        self.setWindowTitle(_tr("Preferences"))
        
        self.showInList.setText(_tr("Show in list : "))
        self.jdirLabel.setText(_tr("Upload J2ME client from "))
        self.examples.setText(_tr("Examples"))
        self.appl.setText(_tr("Applications"))
        self.custom.setText(_tr("Custom Made"))
        self.srv.setText(_tr("Server-mode"))
        self.bem.setText(_tr("Bemused emulation"))
        self.at.setText(_tr("AT-mode"))
        self.iv.setText(_tr("iViewer"))
        self.nonAv.setText(_tr('Non-available'))
        self.updateAppList.setText(_tr("Update application list every"))
        self.secLabel1.setText(_tr("sec."))
        self.secLabel2.setText(_tr("sec."))
        
        self.connBT.setText(_tr("Use Bluetooth connection, channel"))
        self.connTCP.setText(_tr("Use TCP/IP connection, port"))
        self.connWEB.setText(_tr("Use Web Interace, port"))
        self.connAVH.setText(_tr("Advertise service through Avahi"))
        self.connMAN.setText(_tr("Specify options manually"))
        
        self.deviceATL.setText (_tr("Use connect string"))
        self.deviceBmL.setText (_tr("Use connect string"))
        self.deviceIVL.setText (_tr("Use connect string"))
        
        self.labelRunWhen.setText(_tr("Run device browser with timeout"))
        self.addButton.setText(_tr('Add'))
        self.delButton.setText(_tr('Delete'))
        self.jDir.setText(_tr('Choose'))
        self.auto_reconnect.setText(_tr("Auto reconnect"))
        self.autoGnome.setText(_tr("Gnome session"))
        self.autoStart.setText(_tr("Auto startup with"))
        self.autoKDE.setText(_tr("KDE session"))
        self.ok.setText(_tr('OK'))
        self.dirView.headerItem().setText(0,_tr("Directories"))
        self.autoRun.setText(_tr("Run on startup"))
        self.chooseAuto.setText(_tr("Choose"))
        self.cancel.setText(_tr('Cancel'))
        self.downloadJ2MENow.setText(_tr('Download J2ME client from Web'))
        self.checkJ2MENow.setText(_tr('Check J2ME client updates'))
        self.checkJ2ME.setText(_tr('Check J2ME client updates at start'))

    def delete_clicked(self):
        idx = 0
        while idx < self.dirView.topLevelItemCount():
            item = self.dirView.topLevelItem(idx)
            if self.dirView.isItemSelected(item):
                self.dirView.takeTopLevelItem(idx)
                continue
                
            idx = idx + 1 
             
        self.dirsChanged = True

    def add_clicked(self):
        f = QFileDialog().getExistingDirectory(None,_tr('Add'),self.addDir)
        self.addDir = os.path.dirname(str(f))
        
        add = True

        idx = 0
        item = self.dirView.topLevelItem(idx) 
        while item != None:
            if self.addDir == item.text(0):
                add = False
                break
            idx = idx+1 
            item = self.dirView.topLevelItem(idx)
        
        if add:
            lvi = QTreeWidgetItem(self.dirView)
            lvi.setText(0,str(f))

    def chooseAutoStart(self):
        global chooserWin
        self.chooseAuto.setEnabled(False)
        
        chooserWin = Chooser(self)
        chooserWin.show()

    def chooseJ2MEDir(self):
        f = QFileDialog().getExistingDirectory(None,_tr('Choose'),self.addDir)
        self.addDir = os.path.dirname(str(f))
        self.j2meDir.setText(self.addDir)

    def btChangedAction(self,a0):
        global cfgReader
        cfgReader.dvSrvBT_ = str(self.dataBT.text()).strip()
    
    def tcpChangedAction(self,a0):
        global cfgReader
        cfgReader.dvSrvTCP_ = str(self.dataTCP.text()).strip()
    
    def webChangedAction(self,a0):
        global cfgReader
        cfgReader.dvSrvWEB_ = str(self.dataWEB.text()).strip()
    
    def manChangedAction(self,a0):
        global cfgReader
        cfgReader.dvSrvADV_ = str(self.dataMAN.text()).strip()
    
    def deviceBmChangedAction(self,a0):
        global cfgReader
        cfgReader.deviceBm_ = str(self.deviceBm.text()).strip()
    
    def deviceIVChangedAction(self,a0):
        global cfgReader
        cfgReader.deviceIV_ = str(self.deviceIV.text()).strip()

    def updateAppChangedAction(self,a0):
        self.updateAppList.setEnabled((str(self.tmout.text()).strip() != ''))
        self.secLabel1.setEnabled    ((str(self.tmout.text()).strip() != ''))
    
    def browseDevChangedAction(self,a0):
        self.labelRunWhen.setEnabled((str(self.browseTmout.text()).strip() != ''))
        self.secLabel2.setEnabled   ((str(self.browseTmout.text()).strip() != ''))

    def cancel_clicked(self):
        self.hide()
        self.makeGuiSetup()
        sendMainWindow(20005,False)

    def ok_clicked(self):
        global cfgReader
        
        self.setAutoStartup("KDE",   self.autoKDE.isChecked())
        self.setAutoStartup("Gnome", self.autoGnome.isChecked())
        
        cfgReader.autoStart_    = str(self.autoFile.text()).strip()
        cfgReader.doAutoStart_  = self.autoRun.isChecked()
        
        cfgReader.showApps_     = self.appl.isChecked()
        cfgReader.showCustom_   = self.custom.isChecked()
        cfgReader.showExamples_ = self.examples.isChecked()
        cfgReader.showNonavail_ = self.nonAv.isChecked()
        cfgReader.showAt_       = self.at.isChecked()
        cfgReader.showSrv_      = self.srv.isChecked()
        cfgReader.showBm_       = self.bem.isChecked()
        cfgReader.showIView_    = self.iv.isChecked()

        cfgReader.autoReconn_   = self.auto_reconnect.isChecked()
        cfgReader.deviceAT_     = str(self.deviceAT.currentText()).strip()
        cfgReader.deviceBm_     = str(self.deviceBm.text()).strip()
        cfgReader.deviceIV_     = str(self.deviceIV.text()).strip()
        cfgReader.j2meDir_      = str(self.j2meDir.text()).strip()
        cfgReader.checkJ2MEUpdate_ = self.checkJ2ME.isChecked()
        
        tm = str(self.tmout.text()).strip()
        if tm == '':
            tm = '-1'
        if cfgReader.updateTmout_ != int(tm):
            cfgReader.updateTmout_ = int(tm)
            if cfgReader.updateTmout_ < 0:
                cfgReader.updateTmout_ = -1
            
            # start/stop browser
            sendMainWindow(20010,'')

        tm = str(self.browseTmout.text()).strip()
        if tm == '':
            tm = '-1'
        if cfgReader.browseTmout_ != int(tm):
            cfgReader.browseTmout_ = int(tm)
            if cfgReader.browseTmout_ <= 0:
                cfgReader.browseTmout_ = -1
            
            # start/stop updater
            sendMainWindow(20011,'')
        
        cfgReader.cfgDirs = []
        
        idx = 0
        item = self.dirView.topLevelItem(idx)
        while item != None:
            cfgReader.cfgDirs.append(str(item.text(0)))
            idx = idx+1 
            item = self.dirView.topLevelItem(idx)
        
        ret = QMessageBox.Ok
        if cfgReader.cfgDirs == []:
            ret = QMessageBox.warning(self, "kAnyRemote",
                         _tr("There is no item in the list !\nkAnyRemote will not be able to manage any software !"),QMessageBox.Ok,QMessageBox.Cancel);

        if ret == QMessageBox.Ok:
            cfgReader.saveConfig() 
            self.hide()
            
            sendMainWindow(20005,self.dirsChanged)
            self.dirsChanged = False

    def filterChangedAction(self, w):
            self.dirsChanged = True

    def setSensitivity(self):
        self.dataBT.setEnabled(self.connBT.isChecked())
        self.dataTCP.setEnabled(self.connTCP.isChecked())
        self.dataWEB.setEnabled(self.connWEB.isChecked())
        self.connAVH.setEnabled(self.connTCP.isChecked() or self.connWEB.isChecked())
        self.dataMAN.setEnabled(self.connMAN.isChecked())

    def manToggled(self, w):
        global cfgReader
        cfgReader.dvSrvUseADV_ = w
        if w:
            self.connBT.setChecked(False)
            self.connTCP.setChecked(False)
            self.connWEB.setChecked(False)
            self.connAVH.setChecked(False)
            
            cfgReader.dvSrvUseBT_  = False
            cfgReader.dvSrvUseTCP_ = False
            cfgReader.dvSrvUseWEB_ = False
            cfgReader.dvSrvUseAVH_ = False

            if str(self.dataMAN.text()).strip() == '':
                self.dataMAN.setText("-log -s bluetooth:19,tcp:5197,web:5080,avahi")
        self.setSensitivity()

    def btToggled(self, w):
        global cfgReader
        cfgReader.dvSrvUseBT_ = w
        if w:
            self.connMAN.setChecked(False)
            cfgReader.dvSrvUseADV_ = False
            
            if str(self.dataBT.text()).strip() == '':
                self.dataBT.setText("19")
        self.setSensitivity()
        
    def tcpToggled(self, w):
        global cfgReader
        cfgReader.dvSrvUseTCP_ = w
        if w:
            self.connMAN.setChecked(False)
            cfgReader.dvSrvUseADV_ = False
            
            if str(self.dataTCP.text()).strip() == '':
              self.dataTCP.setText("5197")
        self.setSensitivity()
         
    def webToggled(self, w):
        global cfgReader
        cfgReader.dvSrvUseWEB_ = w
        if w:
            self.connMAN.setChecked(False)
            cfgReader.dvSrvUseADV_ = False
            
            if str(self.dataWEB.text()).strip() == '':
              self.dataWEB.setText("5080")
        self.setSensitivity()

    def avhToggled(self, w):
        global cfgReader
        cfgReader.dvSrvUseAVH_ = w
        if w:
            self.connMAN.setChecked(False)
            cfgReader.dvSrvUseADV_ = False
 
        self.setSensitivity()

    def autoRunToggled(self, w):
        self.autoFile.setEnabled(self.autoRun.isChecked())
        self.chooseAuto.setEnabled(self.autoRun.isChecked())

    def setAutoStartup(self, wm, isAuto):
        if wm == 'KDE':
            autopath = os.environ.get("HOME")+os.sep+'.kde'+os.sep+'Autostart'+os.sep+'ganyremote'
            if isAuto:
                if not os.path.exists(autopath):
                    os.system('ln -s `which ganyremote` '+autopath)
            else:
                os.system('rm -f '+autopath)

        elif wm == 'Gnome':  # will work for gnome > 2.14 ?
            cfgpath  = os.environ.get("HOME")+os.sep+'.config'
            autopath = cfgpath+os.sep+'autostart'
            autorun  = autopath+os.sep+'ganyremote.desktop'

            if not os.path.isdir(cfgpath):
                os.mkdir(cfgpath)
            if not os.path.isdir(autopath):
                os.mkdir(autopath)
            if isAuto:
                if not os.path.isfile(autorun):
                    f=open(autorun, 'w')
                    if f:
                        f.write('[Desktop Entry]\n')
                        f.write('Encoding=UTF-8\n')
                        f.write('Name=gAnyRemote\n')
                        f.write('Exec=ganyremote\n')
                        f.write('Icon=ganyremote\n')
                        f.write('Type=Application\n')
                        f.write('Comment=Remote control through bluetooth or IR connection\n')
                        f.write('GenericName=Remote control through bluetoth or IR connection\n')
                        f.write('Categories=Utility;\n')
                        f.close()
            else:
                os.system('rm -f '+autorun)

    def customEvent(self,event):
        if event.type() == 31000:
            self.autoFile.setText(event.getData())
            self.autoFile.setEnabled(True)
            self.chooseAuto.setEnabled(True)
        elif event.type() == 32000:
            self.chooseAuto.setEnabled(True)

###############################################################################        
#
#        Handle Return/Enter in QLineEdit
#
###############################################################################        

class QLineEditEx(QLineEdit):

    def __init__(self,parent = None,toplevel = None):
        QLineEdit.__init__(self,parent)
        self.top = toplevel
        
    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Enter or event.key() == Qt.Key_Return:
            self.top.exec_clicked()
        else:
            QLineEdit.keyPressEvent(self,event)

###############################################################################        
#
#        Custom Event
#
###############################################################################        

class QEventEx(QEvent):

    def __init__(self, eid, data=None):
        QEvent.__init__(self,eid)
        self.data = data

    def getData(self):
        return self.data

###############################################################################        
#
#        kAnyRemote
#
###############################################################################        

class kAnyRemote(QMainWindow):
    def __init__(self,cfgSet):
        QMainWindow.__init__(self)

        global app, debug, guiMode, cfgReader
        
        self.statusBar()
        
        row = 3
        if debug:
            row = 4

        if guiMode == 'simple':
            row = row - 1

        self.setCentralWidget(QWidget(self))
        kAnyRemoteLayout = QGridLayout(self.centralWidget())
        kAnyRemoteLayout.setMargin(6)
        kAnyRemoteLayout.setSpacing(6)

        self.stop_button  = QPushButton(loadIcon("dialog-close","stop"), _tr("Stop"),  self.centralWidget())
        self.run_button   = QPushButton(loadIcon("system-run",  "run"),  _tr("Start"), self.centralWidget())
        
        kAnyRemoteLayout.addWidget(self.run_button, row,0,1,4)
        kAnyRemoteLayout.addWidget(self.stop_button,row,4,1,4)

        self.listView1 = QTreeWidget(self.centralWidget())
        self.listView1.setColumnCount(5)
        self.listView1.headerItem().setText(0,_tr("Application")+"    ")
        self.listView1.headerItem().setText(1,_tr("Status")+"         ")
        self.listView1.headerItem().setText(2,_tr("Mode")+"    ")
        self.listView1.headerItem().setText(3,_tr("Type")+"    ")
        self.listView1.headerItem().setText(4,_tr("F")+"    ")
        
        self.listView1.header().setResizeMode(0,QHeaderView.ResizeToContents)
        self.listView1.header().setResizeMode(1,QHeaderView.ResizeToContents)
        self.listView1.header().setResizeMode(2,QHeaderView.ResizeToContents)
        self.listView1.header().setResizeMode(3,QHeaderView.Stretch)
        
        self.listView1.setSelectionMode(QAbstractItemView.SingleSelection)
        
        self.listView1.hideColumn(4)
        self.listView1.setSortingEnabled(True)
        self.listView1.sortByColumn(0,Qt.AscendingOrder)

        self.connect(self.listView1,SIGNAL('itemClicked (QTreeWidgetItem *,int)'),self.listClicked)
        self.connect(self.listView1,SIGNAL('itemDoubleClicked (QTreeWidgetItem *,int)'), self.listDClicked)
        self.connect(self.listView1,SIGNAL('currentItemChanged (QTreeWidgetItem *,QTreeWidgetItem *)'), self.cursorMoved)

        kAnyRemoteLayout.addWidget(self.listView1,0,0,1,8)
        
        self.details = QTreeWidget(self.centralWidget())
        self.details.setHeaderHidden(True)
        self.details.setColumnCount(1)

        self.details.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Maximum)
        self.details.setRootIsDecorated(True)
        self.details.setSelectionMode(QAbstractItemView.NoSelection)
        self.details.setFrameStyle(QFrame.NoFrame)

        p = QPalette(self.details.palette())
        p.setColor(QPalette.Base, QApplication.palette().color(QPalette.Window))
        self.details.setPalette(p)
        
        self.connect(self.details,SIGNAL('itemExpanded(QTreeWidgetItem *)'),self.detailExpanded)
        self.connect(self.details,SIGNAL('itemCollapsed(QTreeWidgetItem *)'),self.detailCollapsed)
        
        kAnyRemoteLayout.addWidget(self.details,1,0,1,8)
  
        self.detailsHead = QTreeWidgetItem(self.details)
        self.detailsHead.setText(0,_tr("Details"))       
        self.detailsHead.setExpanded(False)
        self.detailsItem = QTreeWidgetItem(self.detailsHead)
        self.detailsItem.setText(0,'') 
        
        h = self.details.visualItemRect(self.detailsHead).height()
        if h == 0: h = 18
        self.details.setMinimumHeight(h)
        self.details.setMaximumHeight(h)

        if guiMode == 'expert':
            self.cfgFile = QLineEdit(self.centralWidget())
            kAnyRemoteLayout.addWidget(self.cfgFile,2,0,1,6)
            self.choose = QPushButton(loadIcon("document-open","fileopen"), _tr("Choose"), self.centralWidget())
            kAnyRemoteLayout.addWidget(self.choose,2,6,1,2)

        if debug:
            self.command = QLineEditEx(self.centralWidget(),self)
            kAnyRemoteLayout.addWidget(self.command,3,0,1,6)
            self.execcmd = QPushButton(loadIcon("system-run","exec"), _tr("Execute Command"), self.centralWidget())
            kAnyRemoteLayout.addWidget(self.execcmd,3,6,1,2)
            self.execcmd.setEnabled(True)


        # File menu
        self.fileExitAction = QAction(loadIcon("application-exit","exit"),     _tr("Quit"), self)
        self.edit_file      = QAction(loadIcon("document-edit",   "edit"),     _tr("Edit"), self)
        self.start          = QAction(loadIcon("system-run",      "run"),      _tr("Start"),self)
        self.stop           = QAction(loadIcon("dialog-close",    "stop"),     _tr("Stop"), self)
        self.update         = QAction(loadIcon("reload", "appointment-recurring"), _tr("Update Status"), self)
        self.close_window   = QAction(loadIcon("edit-delete", "fileclose"),    _tr("Close Window"), self)
        
        # Edit menu
        self.save_prefs = QAction(loadIcon("document-save","filesave"),   _tr("Save"),               self)
        self.properties = QAction(loadIcon("configure","configure"),      _tr("Preferences"),             self)
        self.chkCfg     = QAction(loadIcon("dialog-ok-apply","button_ok"),_tr("Check Configuration"),self)
        self.dbrowser   = QAction(loadIcon("zoom-in","filefind"),         _tr("Device Browser"),     self)
        
        # Help menu
        self.helpContentsAction = QAction(loadIcon("help-contents", "help"), _tr("Help"),  self)
        self.helpAboutAction    = QAction(loadIcon("help-about",    "rating"),  _tr("About"), self)
        
        self.start.setEnabled(False)

        self.Menu = self.menuBar()

        self.fileMenu = self.Menu.addMenu(_tr("File"));
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.edit_file)
        self.fileMenu.addAction(self.start)
        self.fileMenu.addAction(self.stop)
        self.fileMenu.addAction(self.update)
        self.fileMenu.addAction(self.close_window)
        self.fileMenu.addAction(self.fileExitAction)

        self.cfgMenu = self.Menu.addMenu(_tr("Setup"))
        self.cfgMenu.addAction(self.dbrowser)
        self.cfgMenu.addAction(self.properties)
        self.cfgMenu.addAction(self.chkCfg)
        self.cfgMenu.addAction(self.save_prefs)

        self.helpMenu = self.Menu.addMenu(_tr("Help"))
        self.helpMenu.addAction(self.helpAboutAction)
        self.helpMenu.addAction(self.helpContentsAction)

        self.Menu.addSeparator()

        self.languageChange()

        self.resize(QSize(370,300).expandedTo(self.minimumSizeHint()))

        self.connect(self.fileExitAction,SIGNAL("triggered()"),self.fileExit)
        self.connect(self.edit_file,     SIGNAL("triggered()"),self.edit_file_activated)
        self.connect(self.start,         SIGNAL("triggered()"),self.runAction)
        self.connect(self.stop,          SIGNAL("triggered()"),self.stopAction)
        self.connect(self.update,        SIGNAL("triggered()"),self.rescan_dirs_clicked)
        self.connect(self.close_window,  SIGNAL("triggered()"),self.close_window_clicked)
        
        self.connect(self.dbrowser  ,    SIGNAL("triggered()"),self.showBrowser)
        self.connect(self.save_prefs,    SIGNAL("triggered()"),self.saveCfg)
        self.connect(self.properties,    SIGNAL("triggered()"),self.showConfDialog)
        self.connect(self.chkCfg,        SIGNAL("triggered()"),self.showChkWin)

        self.connect(self.helpContentsAction,SIGNAL("triggered()"),self.helpAction)
        self.connect(self.helpAboutAction,   SIGNAL("triggered()"),self.helpAbout)
        
        if guiMode == 'expert':
            self.connect(self.choose,  SIGNAL("clicked()"),self.choose_clicked)
        self.connect(self.stop_button, SIGNAL("clicked()"),self.stopAction)
        self.connect(self.run_button,  SIGNAL("clicked()"),self.runAction)
        self.connect(self,             SIGNAL("destroyed()"),self.close_window_clicked)
        
        h = 500
        if debug:
            h = 470
            self.connect(self.execcmd,SIGNAL("clicked()"),self.exec_clicked)
        
        self.resize(QSize(470,h).expandedTo(self.minimumSizeHint()))
        self.win_width = 470
        
        self.stop.setEnabled(False)
        self.stop_button.setEnabled(False)
        
        if guiMode == 'expert':
            self.cfgFile.setText(cfgReader.lastCfgFile_)

        self.cfgWin        = None
        self.frontEnd      = None
        self.statusUpdater = None                
        
        # will send event to start (if needed) StatusUpdater 
        #self.populateCfgFiles()        
        
        # will start device browser (if needed)
        startBtComm()
        
        self.setStatusStopped()
        
        if not cfgSet or cfgReader.j2meDir_ == '':
            self.showWizard(cfgSet,cfgReader.j2meDir_)
    
    def languageChange(self):
        global debug, guiMode
    
        self.setWindowTitle("kAnyRemote")
        self.listView1.headerItem().setText(0,_tr("Application"))
        self.listView1.headerItem().setText(1,_tr("Status"))
        self.listView1.headerItem().setText(2,_tr("Mode"))
        self.listView1.headerItem().setText(3,_tr("Type"))
        if guiMode == 'expert':
            self.choose.setText(_tr('Choose'))
        if debug:
            self.execcmd.setText(_tr("Execute Command"))
        
        self.close_window.setText(_tr("Close Window"))
        self.stop_button.setText(_tr("Stop"))
        self.run_button.setText(_tr("Start"))
        self.fileExitAction.setText(_tr("Quit"))
        
        self.helpContentsAction.setText(_tr("Help"))
        
        self.helpAboutAction.setText(_tr("About"))
        
        self.edit_file.setText(_tr("Edit"))
        self.edit_file.setToolTip(_tr("Edit configuration file"))
        self.start.setText(_tr("Start"))
        self.stop.setText(_tr("Stop"))
        self.stop.setToolTip(_tr("Stop anyRemote"))
        self.save_prefs.setText(_tr("Save"))
        self.properties.setText(_tr("Preferences"))
        self.chkCfg.setText(_tr("Check Configuration"))
        self.dbrowser.setText(_tr("Device Browser"))
        
        self.fileMenu.menuAction().setText(_tr("File"))
        self.cfgMenu.menuAction().setText(_tr("Setup"))
        self.helpMenu.menuAction().setText(_tr("Help"))
  
    def showWizard(self, cfgdirs, jclient):
        if not cfgdirs:
            ret = QMessageBox.information(self, "kAnyRemote",
                     _tr("This is the first time kAnyRemote runs.\nPlease specify directories with anyRemote configuration files."),QMessageBox.Ok);
            self.showConfDialog()
        
        if jclient == '': 
            ret  = yesno(self,_tr('Would You like to download J2ME client from Web ?'))
            if ret:
                if not self.cfgWin:
                    self.cfgWin = Preferences();
                self.cfgWin.uploadJ2MEWeb()

    def showConfDialog(self):
        if not self.cfgWin:
            self.cfgWin = Preferences();
        self.cfgWin.show()
        self.properties.setEnabled(False)

    def showChkWin(self):
        showChkCfgWin()

    def saveCfg(self):
        global cfgReader
        cfgReader.saveConfig()
    
    def showBrowser(self):
        showBrowserWin()

    def getStatus(self,isRun,status):
       if status == AR_MANAGED and isRun == 'NOK':
           status = AR_AVAIL
       elif status == AR_AVAIL and isRun == 'OK':
           status = AR_RUNNING
       elif status == AR_RUNNING and isRun == 'NOK':
           status = AR_AVAIL
 
       return status
 
    def addRow(self,rowData):
        #[aName, pbuf, isRun, status, aMode, aType, idx]
       lvi = QTreeWidgetItem(self.listView1)

       ic = loadAppIcon(rowData[1])

       lvi.setIcon(0,ic)
       lvi.setText(0,rowData[0])       
       lvi.setText(1,self.getStatus(rowData[2],rowData[3]))
       lvi.setText(2,rowData[4])
       lvi.setText(3,rowData[5])
       lvi.setText(4,str(rowData[6]))
  
    def listClicked(self, listItem, column):
        global debug, cfgReader, appData, guiMode
        try:
            cfgReader.lastCfgFile_ = appData[int(str(listItem.text(4)))][5]
            desc = appData[int(str(listItem.text(4)))][9]
            self.setDetails(desc)

            if guiMode == 'expert':
                self.cfgFile.setText(cfgReader.lastCfgFile_)
        except AttributeError:
            if debug: print 'kAnyRemote.listClicked: AttributeError'
        

    def listDClicked(self, listItem, column):
        self.listClicked(listItem, column)
        self.runAction()

    def cursorMoved(self,listItem,previous):
        global debug, cfgReader, appData, guiMode
        try:
            cfgReader.lastCfgFile_ = appData[int(str(listItem.text(4)))][5]
            desc = appData[int(str(listItem.text(4)))][9]
            self.setDetails(desc)
        
            if guiMode == 'expert':
                 self.cfgFile.setText(cfgReader.lastCfgFile_)
        except AttributeError, KeyError:
            if debug: print 'kAnyRemote.cursorMoved: an Error'
        
    def fileExit(self):
        global app, quitFlag, debug, jup
        
        if debug: print "kAnyRemote.fileExit"
        quitFlag = True
        
        closeDetailsWin()
        closeBrowserWin()
        closeChkCfgWin()
        closeChooserWin()
        
        self.stopUpdater()
        stopFrontend()
        stopBtComm()
        stopJCUploader()
        stopPBar()
        
        time.sleep(0.5)
	
        app.quit()

    # open web browser on docs page if found ?
    def helpAction(self):
    
        app = ''
        apps = ['xdg-open', 'firefox', 'konqueror', 'chromium']
        for test in apps:
            isInst = isInstalled(test) 
            if isInst == 'OK':
                app = test
        if app == '':
            errorBox(_tr('Can not find browser to show help !'))
            return

        docpath = ''
        docDirs = ['/usr/share/doc/anyremote*/*html', 
                   '/usr/share/anyremote*/*html', 
                   '/usr/share/doc/anyremote-doc', 
                   '/usr/local/share/doc/anyremote*/*html', 
                   '/usr/local/share/anyremote*/*html']

        for docDir in docDirs:
            dirv = glob.glob(docDir)
            if len(dirv) > 0 and os.path.isdir(dirv[0]):
                docpath = dirv[0]
                break
        if docpath == '':
            errorBox(_tr('Can not find documentation !'))
            return
        
        cmd = app + ' ' + docpath + os.sep + 'k-shots.html &'
        if debug: print cmd
        os.system(cmd)

    def helpAbout(self):
        global app
        a = QMessageBox(QMessageBox.Information, "About kAnyRemote", "<h2>kAnyRemote v6.3.5</h2>", QMessageBox.Ok, self) 
        a.setIconPixmap(getPixmap("kanyremote"))
        a.setInformativeText("<center>Copyright 2007-2013<p>Mikhail Fedotov<p><a href=\"http://anyremote.sf.net\">http://anyremote.sf.net</a></center>");
        a.setDetailedText("KDE front-end for anyRemote (bluetooth remote control for PC).\nThe code is licensed under the GNU Public licence.")
        a.show()

    def edit_file_activated(self):
        global cfgReader
        if cfgReader.lastCfgFile_:
            self.eWin = EditWin(cfgReader.lastCfgFile_,self)
            self.eWin.show()

    def choose_clicked(self):
        fileName = QFileDialog.getOpenFileName(None,"", "");
        self.cfgFile.setText(fileName)

    def rescan_dirs_clicked(self):
        self.listView1.clear()
        self.populateCfgFiles()
    
    def closeEvent(self, event):
        event.ignore()
        self.close_window_clicked()
    
    def close_window_clicked(self):
        global systray
        if systray:
            self.hide()
        else:
            self.fileExit()

    def stopAction(self):
        global debug
        if debug: print "kAnyRemote.stopAction()"

        self.saveCfg()
        
        # To avoid socket.error: (98, 'Address already in use') 
        # it needs to close client socket first
        killAnyRemote()

        self.setStatusStopped()
   
    def minMaxAction(self):
        self.setVisible(not self.isVisible())

    def exec_clicked(self):
        global cmdToSend, debug
       
        if debug:
            print 'Add to queue ' + self.command.text()
            cmdToSend = self.command.text()

    def runAction(self):
        global debug, cfgReader

        if debug: print "kAnyRemote.runAction()"
        
        self.saveCfg()
        
        self.setStatusStopped()
        
        cfile = cfgReader.lastCfgFile_
        if guiMode == 'expert':
            cfile = self.cfgFile.text()

        startAnyRemote(cfile)        
                            
    def restartUpdater(self):
        self.stopUpdater()
        self.startUpdater()

    def startUpdater(self):
        global cfgReader
        if cfgReader.updateTmout_ > 0:
            self.statusUpdater = StatusUpdater(cfgReader.updateTmout_)
            self.statusUpdater.start()

    def stopUpdater(self):
        try:
            self.statusUpdater.stop()
        except AttributeError, NameError:
            pass
        time.sleep(0.5)
        self.statusUpdater = None

    def showEvent(self, event):
        global debug
        if debug: print 'showEvent'
        self.populateCfgFiles()

    def resizeEvent(self, event):
        w = self.width() - self.win_width
        
        if w > -5 and w < 5: # resize is too small
           return
        
        self.win_width = self.width()  
        desc = str(self.detailsItem.text(0)).replace('\n',' ')
        self.setDetails(desc)

    def populateCfgFiles(self):
        global debug
        if debug: print 'populateCfgFiles'
        
        try:
            if cfgFileReaderFlag:
                return
        except NameError:
            pass
        
        self.stopUpdater()
        cfgFileReader = CfgFileReader()
        cfgFileReader.start()

    def autoStartBackend(self):
        global cfgReader, frontEnd, cfgFileReaderFlag

        if cfgReader.doAutoStart_ and cfgReader.autoStart_ != '':

            if not frontEnd or not frontEnd.ready() or cfgFileReaderFlag:
                # respawn timer
                QTimer.singleShot(200, self.autoStartBackend)
                return 

            self.setStatusStopped()
            startAnyRemote(cfgReader.autoStart_)
        
    def setTempStatus(self, text):
        self.statusBar().clearMessage()
        self.statusBar().showMessage(text)

    def setStatustext(self,text):
        self.statusValue = text
        self.setTempStatus(text)
        
    def setStatusStopped(self):
        setTrayIcon("kanyremote_off")
        self.setStatustext(_tr('anyRemote stopped'))
        self.stop.setEnabled(False)
        self.start.setEnabled(True)
        self.stop_button.setEnabled(False)
        self.run_button.setEnabled(True)

    def setStatusDisconnected(self):
        global cfgReader
        
        setTrayIcon("kanyremote_light")
        self.setStatustext(_tr('Ready to connect on')+' '+cfgReader.getConnectStatusString())
        self.stop.setEnabled(True)
        self.start.setEnabled(False)
        self.stop_button.setEnabled(True)
        self.run_button.setEnabled(False)

    def setStatusConnected(self):
        global cfgReader
        
        setTrayIcon("kanyremote_small")
        msg = _tr('Connected to phone')
        if cfgReader.dvSrvUseWEB_:
            msg = _tr('Connected') 
        self.setStatustext(msg)
        
    def listUpdate(self, data):
        #print 'listUpdate',data
        st = self.getStatus(data[2],data[1])
        
        idx = 0
        item = self.listView1.topLevelItem(idx) 
        while item != None:
            try:
                if int(item.text(4)) == data[0]:
                    item.setText(1,st)
                    break
            except ValueError:
                pass
            idx = idx+1 
            item = self.listView1.topLevelItem(idx)

    def sliceString(self, string, font, width):

        fm =  QFontMetrics(font)
        sliced = ''
        line   = ''
        
        wordList = string.split(' ')
        for word in wordList:
            line1 = line+' '+word
            if fm.width(line1) > width:
                if len(sliced) != 0:
                    sliced = sliced + '\n'
                sliced = sliced + line
                line = word
            else:
                line = line1
                
        return sliced + '\n' + line

    def setDetails(self, desc):
        slicedString = self.sliceString(desc, self.details.font(), self.width()-80)
        self.detailsItem.setText(0,slicedString.lstrip())
        cnt = slicedString.count('\n')
        
        if self.detailsHead.isExpanded():
            h = self.details.visualItemRect(self.detailsHead).height()*(cnt+2)
            if h == 0: h = 18*(cnt+2)
            self.details.setMinimumHeight(h)
            self.details.setMaximumHeight(h)

    def selectLastInList(self):
        global cfgReader
    
        idx = None
        for k, v in appData.iteritems():
            if v[5] == cfgReader.lastCfgFile_:
                idx = k

        idx = 0
        item = self.listView1.topLevelItem(idx)
        while item != None:
            try:
                if int(str(item.text(4))) == idx:
                    self.listView1.setCurrentItem(item)
                    
                    desc = appData[int(str(item.text(4)))][9]
                    self.setDetails(desc)
 
                    return
            except ValueError:
                pass   
            idx = idx+1 
            item = self.listView1.topLevelItem(idx)
    
    def translateMsg(self, data):
        global debug
        if debug: print 'translateMsg '+data

        if data == '':
           return
        elif data == 'Exiting':
           self.setStatusStopped()
           return
        elif data == 'Connected':
           self.setStatusConnected()
           return
        elif data == 'Disconnected':
           self.setStatusDisconnected()
           return
        if data == '(Init)':
           msg = 'anyRemote initialized'
        else:
           if debug: print 'translateMsg BlinkThread'
           
           # Just key press
           setTrayIcon("kanyremote_flash") 
           QTimer.singleShot(200, resetIcon)  
 
           if debug:
               msg = data
           else:
               return
        
        self.setStatustext(msg)

    def customEvent(self,event):
        global appData, debug
        
        if event.type() == 20000:
           self.setStatusStopped()
        elif event.type() == 20003:
           cfgFile = getResult('ps aux |grep anyremote|grep cfg|awk \'{n=split($0,arr);print arr[n-2];}\'', 'frontend')

           if cfgFile != '':
                for k, v in appData.iteritems():
                    if appData[k][5] == cfgFile:
                        appData[k][6] = AR_MANAGED
                        self.listUpdate([k,appData[k][6],'OK'])
           self.setStatusDisconnected()
        elif event.type() == 20001:
           setTrayIcon("kanyremote_flash")
        elif event.type() == 20002:
           setTrayIcon("kanyremote_small")
        elif event.type() == 20005:
           self.cfgWinClosed(event.getData())
        elif event.type() == 20006:
           self.listUpdate(event.getData())
        elif event.type() == 20008:
           self.dcopHandleSend(event.getData())
        elif event.type() == 20009:
           self.dcopHandleGetMode()
        elif event.type() == 20010:
           self.restartUpdater()
        elif event.type() == 20011:
           restartBtComm()
        elif event.type() == 20012:
           for k, v in appData.iteritems():
               if appData[k][6] == AR_MANAGED:
                   aRun = appData[k][3]
                   isRun = ''
                   if aRun != '':
                        isRun  = getResult(aRun,'main')
                    
                        if isRun == 'OK':
                            appData[k][6] = AR_RUNNING
                        else:
                            appData[k][6] = AR_AVAIL
                   else:
                        appData[k][6] = '' 

                   self.listUpdate([k,appData[k][6],isRun])
        elif event.type() == 20014:
            ret = yesno(self,_tr("New version of J2ME client is available. Would You like to download it ?"))
            if ret :
                if not self.cfgWin:
                    self.cfgWin = Preferences();
                self.cfgWin.uploadJ2MEWeb() 
        elif event.type() == 20015:
            infoBox(self,event.getData())
        elif event.type() == 20016:
            errorBox(self,event.getData())
        elif event.type() == AR_CODE_LOADED:
           value = int(event.getData())
           if value >= 0:
               self.setTempStatus(str(value))
           else:
               self.setStatustext(self.statusValue)
               self.listView1.clear()
	       
	       t1 = datetime.datetime.now()
	       
               for k, v in appData.iteritems():
                   self.addRow([appData[k][0],appData[k][1],appData[k][4],appData[k][6],appData[k][7],appData[k][8],k])
	       
	       t2 = datetime.datetime.now()
	       if debug: print "ELAPSED ",(t2-t1)
	       
               self.selectLastInList()
               self.restartUpdater()
        elif event.type() == 20018:
           self.stopProgressBar()
        elif event.type() == 20019:
           self.startProgressBar(event.getData())
        elif event.type() == 20020:
           self.showDevDetails(event.getData())
        elif event.type() == 20021:
           self.writeProgressBar(event.getData())
        elif event.type() == 20022:
           self.listView1.clear()
        else:
           self.translateMsg(str(event.getData()))
           
    def pushTrayIcon(self):
        if self.isShown == 1:
            self.hide()
            self.isShown = 0
        else:
            self.show()
            self.isShown = 1
            
    def cfgWinClosed(self, isChanged):
        self.properties.setEnabled(True)
        if isChanged:
            self.populateCfgFiles()
            
    def dcopHandleSend(self, cmd):
        global cmdToSend
        if debug: print 'Add to queue ' + cmd
        cmdToSend = cmd
    
    def detailExpanded(self, item):
        cnt = str(self.detailsItem.text(0)).count('\n')
        h = self.details.visualItemRect(self.detailsHead).height()*(cnt+2)
        if h == 0: h = 18*(cnt+2)
        self.details.setMinimumHeight(h)
        self.details.setMaximumHeight(h)

    def detailCollapsed(self, item):
        h = self.details.visualItemRect(self.detailsHead).height()
        if h == 0: h = 18
        self.details.setMinimumHeight(h)
        self.details.setMaximumHeight(h)
    
    def  stopProgressBar(self):
        global pbar, pbarTimer,debug
    
        if debug: print 'stopProgressBar'

        try:
            pbarTimer.stop()
        except AttributeError:
            pass
        
        try:
            pbar.hide()
            pbar.cancel()
            pbar = None
        except AttributeError, NameError:
            pass
            
    def startProgressBar(self,text):
        global debug, pbar, pbarTimer
        
        if debug: print 'startProgressBar'
    
        pbar = PBar(text,100)
        timerPBar()

    def writeProgressBar(self,text):
        global pbar

        try:
            pbar.setLabelText(text)
        except AttributeError, NameError:
            pass

    def showDevDetails(self,dataList):
        global detailsWin, cfgReader
        detailsWin = DeviceDetail(dataList[0], dataList[1], dataList[2], dataList[3], dataList[4], dataList[5], cfgReader.j2meDir_)
        detailsWin.show()

##################################################################################
#
# Utilities functions
#
##################################################################################

def getHttp(hname,fname,tmp):
    global debug

    try:
        conn = httplib.HTTPConnection(hname,80,timeout=10)
    # old pythons (<2.6)
    except TypeError:
        conn = httplib.HTTPConnection(hname)

    try:
        conn.request("GET", fname)
    except Exception: 
        sendMainWindow(20016, _tr('Can not establish the connection !'))
        return False
        
    r = conn.getresponse()

    if debug: print fname, r.status, r.reason,r.getheader('content-length')
    
    ret = True
    
    if r.status == httplib.OK:
        if debug: print 'download',fname
        
        try:
            data = r.read()
        except Exception:
            sendMainWindow(20016, _tr('Download failed !'))
            return False
        
        f=open(os.environ.get("HOME")+os.sep+'.anyRemote'+fname+tmp, 'w')
        if f:
            f.write(data)
            f.close()
    else:
        if tmp == "":
            sendMainWindow(20016, _tr('Can not download ')+hname+fname)
            ret = False

    conn.close()

    return ret
    
def uploadJ2MEWebGui(fname, strip=False):
    global debug
    
    if debug: print 'uploadJ2MEWebGui',fname
    
    writePBar(_tr('Downloading')+' '+fname)
    
    if not getHttp("anyremote.sourceforge.net",os.sep+fname,""):
        stopPBar()
        if debug: print 'uploadJ2MEWebGui: fails to upload',fname
        return False
    
    if strip:
        f1 = os.environ.get("HOME")+os.sep+'.anyRemote'+os.sep+fname
        os.system('rm -f '+f1+'.tmp; cat '+f1+'|sed \'s/MIDlet-Jar-URL: http:\/\/anyremote.sourceforge.net\//MIDlet-Jar-URL: /\' > '+f1+'.tmp;mv '+f1+'.tmp '+f1);
    
    return True

def getJ2MEClientVersion(fname):
    global debug
    if debug: print 'Check version of J2ME client from file',fname
    return getResult('cat '+fname+'|grep MIDlet-Version|tr -d \" \"|cut -f 2 -d \":\"','main')

def checkJ2MEClientUpdate():
    global debug
    
    if not getHttp("anyremote.sourceforge.net",os.sep+"anyRemote-16.jad",".check"):
        return "-1"
        
    newver = getJ2MEClientVersion(os.environ.get("HOME")+os.sep+'.anyRemote'+os.sep+'anyRemote-16.jad.check')
    oldver = getJ2MEClientVersion(getJ2MEPath()+os.sep+'anyRemote-16.jad')
    
    if debug: print 'compare new=',newver,' and old=',oldver
    
    nvers = newver.split('.')
    overs = oldver.split('.')
    
    l = len(nvers)
    if len(overs) > l: 
        l = len(overs)
    
    foundnew = False
    for i in range(l):
        
        if len(overs) < i:
            oi = 0
        else:
            oi = overs[i]
            
        if len(nvers) < i:
            ni = 0
        else:
            ni = nvers[i]
        
        #if debug: print '(',i,') compare new=',ni,' and old=',oi
        if ni > oi:
            foundnew = True
            break

    if (foundnew):
        return  newver
        
    return ""

#
#
#
def getMode(cfile):
    global appData
    for k, v in appData.iteritems():
        if appData[k][5] == cfile:
            return appData[k][7]
    return ''

def killAnyRemote():
    os.system('killall -2 anyremote 2> /dev/null')
    
def startAnyRemote(cfile):
    global debug, cfgReader, port
    
    killAnyRemote()
    
    tool = isInstalled('anyremote')
    if tool == 'NOK':
        return

    time.sleep(0.5)
    
    useType = getMode(cfile)
    
    mode = 'Server'
    if cfgReader.showAt_:
        mode = 'AT'
    if cfgReader.showBm_:
        gui = 'Bemused'
    if cfgReader.showIView_:
        mode = 'iViewer'

    log = ''
    if debug:
        log = ' -log'
   
    dev = ''
    rconn = ''
    
    if mode == 'Server':
        connStr = cfgReader.getConnectString()
        if connStr != '':
                dev = ' -s '+connStr
  
    elif mode == 'AT':
        if cfgReader.deviceAT_ != '':
                dev = ' -s '+cfgReader.deviceAT_
    
        if cfgReader.autoReconn_ != '':
            rcomm = ' -a '
        
    elif mode == 'Bemused':
        if cfgReader.deviceBm_ != '':
                dev = ' -s '+cfgReader.deviceBm_
    
    elif mode == 'iViewer':
        
        if cfgReader.deviceIV_ != '':
                dev = ' -s '+cfgReader.deviceIV_
    
    else:
         if cfgReader.autoReconn_ != '':
            rconn = ' -a '

                
    to_path = os.environ.get("HOME") + os.sep + '.anyRemote' + os.sep

    cmd = 'anyremote -fe ' + port + log + ' -f ' + str(cfile) + dev + rconn + ' > '+ to_path + 'anyremote.stdout &'
    if debug: print cmd
    os.system(cmd)
 
#####################################################################################    

def sendEvent(receiver, eid, data):
    global quitFlag, app
    
    if quitFlag: return
    
    event = QEventEx(eid,data)
    app.postEvent(receiver, event)
    
def loadFromTheme(theme,icon):
    dir = '/usr/share/icons/'+theme+'/16x16'
    if not os.path.exists(dir):
    	return QPixmap()
    	
    iFile = getResult('find '+dir+' -name '+icon+'.[ps][nv]g|head -1', 'main')
    
    if iFile != '':
    	pixmap = QPixmap(iFile)
    	if not pixmap.isNull():
    	    return pixmap

    return QPixmap()

def loadPixmap(icon):
    try:
        curTheme = str(QIcon.themeName())

        if QIcon.hasThemeIcon(icon):
            ic = QIcon.fromTheme(icon)
            return ic.pixmap(16,16)

        themes = ["oxygen","crystalsvg","Humanity","Tango","gnome","hicolor"]
        for theme in themes:
            if theme == curTheme:
               continue
            px = loadFromTheme(theme,icon)
            if not px.isNull():
                return px
    # fix QT versioning issues
    except AttributeError:
        pass
    
    # hardcode it, last resort
    pixmap = QPixmap("/usr/share/pixmaps/"+icon+".svg")

    if pixmap.isNull():
        pixmap = QPixmap("/usr/share/pixmaps/"+icon+".png")
    
    # use from current directory, the latest resort
    if debug and pixmap.isNull():
        pixmap = QPixmap("data/"+icon+".svg")
    
    if debug and pixmap.isNull():
        pixmap = QPixmap("data/"+icon+".png")
        
    if debug and pixmap.isNull(): 
        print "loadPixmap NO PIXMAP",icon
    
    return pixmap 

def getPixmap(icon):
    if icon.endswith('.png') or icon.endswith('.svg'):
        icon = icon[0:-4]
    
    pixmap = QPixmapCache.find(icon)
    
    if pixmap == None:
        pixmap = loadPixmap(icon)
        QPixmapCache.insert(icon,pixmap)
    return pixmap

def getIcon(icon):

    if icon.endswith('.png') or icon.endswith('.svg'):
        icon = icon[0:-4]
    try:
        if QIcon.hasThemeIcon(icon):
            ic = QIcon.fromTheme(icon)
            return ic
    # fix QT versioning issues
    except AttributeError:
        pass

    return QIcon(getPixmap(icon))

# Load icon for cfg. file.
def loadAppIcon(name1):
    ic = getIcon(name1)
    if ic.isNull():
        ic = QIcon(getPixmap("document-open"))
    return ic

# Load icon for menu/button/etc.
def loadIcon(name1,name2):

    ic = getIcon(name1)
    
    if ic.isNull():
        ic = getIcon(name2)
    
    return ic

def setTrayIcon(iconName):
    global systray
    if systray:
        systray.setIcon(QIcon(getPixmap(iconName)))

def resetIcon():
    setTrayIcon("kanyremote_small")

def yesno(widget, message):
    ret = QMessageBox.question(widget,"kAnyRemote",message,QMessageBox.Yes|QMessageBox.Default,QMessageBox.No|QMessageBox.Escape)
    return (ret == QMessageBox.Yes)

def errorBox(widget, msg):
    ret = QMessageBox.warning(widget,"kAnyRemote",msg,QMessageBox.Ok);

def infoBox(widget, msg):
    ret = QMessageBox.warning(widget,"kAnyRemote",msg,QMessageBox.Ok);

def infoMessage(msg):
    sendMainWindow(20015, msg)

def codeMessage(code):
    sendMainWindow(code, '')

def codeMessage2(code,val):
    sendMainWindow(code, val)

def statusMessage(val):
    sendMainWindow(val,'')

def getJ2MEPath():
    path = ''
    if os.path.exists(os.environ.get("HOME") + os.sep + '.anyRemote' + os.sep + 'anyRemote-16.jad'):
        path = os.environ.get("HOME") + os.sep + '.anyRemote'
    return path

def isInstalled(app):
    dirs = os.getenv('PATH').split(':')
    for d in dirs:
        if os.path.exists(d+'/'+app):
            return 'OK'
    return 'NOK'

def reqVersion(cmd):
    res = getResult(cmd,'main')
    if res == 'OK':
         return 'OK'
    return 'NOK'
        
def getResult(cmd, suffix):
    #print 'getResult',cmd, suffix

    toFile = os.environ.get("HOME") + os.sep + '.anyRemote' + os.sep + 'kanyremote-' + suffix + '.tmp'
    os.system(cmd + '> ' + toFile)
    line = getLineTmpFile(toFile)
    return line.replace('\n','')

def getLineTmpFile(toFile):
    fd = open(toFile,'r')
    ln = ''
    if fd:
            ln=fd.readline()
            fd.close()
    return ln
   
def clearAppsList():   
    global appData
    appData.clear()

def addAppToList(aName, aIcon, app, aRun, isRun, cfgFile, status, aMode, aType, aDesc):
    global appData
     
    if aIcon == '':
        aIcon = 'document-open.png'
    
    idx = len(appData)
    
    for oneMode in aMode: 
        appData[idx] = [aName, aIcon, app, aRun, isRun, cfgFile, status, _tr(oneMode), _tr(aType), aDesc]
        idx = idx + 1

#####################################################################################    

def addDevice(v1, v2, v3, v4, v5):
    global bt_devices
    bt_devices[v1] = [v1,v2,v3,v4,v5,'']

def saveDevices():

    global bt_devices

    # anyRemote related part
    cfg = os.environ.get("HOME")+os.sep+'.anyRemote'
    if os.path.exists(cfg):
            pass
    else:
            os.mkdir(cfg)

    f=open(cfg + os.sep + AR_FILE_DEVICES, 'w')
    if f:
            for k, v in bt_devices.iteritems():

                row = bt_devices[k]
                v0 = row[0]
                v1 = row[1]
                v2 = row[2]
                v3 = row[3]
                v4 = row[4]
                
                f.write('Device='+v0+','+v1+','+v2+','+v3+','+v4+'\n')

            f.close()

#####################################################################################    

def btVerify():
    hcid = getResult('echo \'A=`ps -ef|grep hcid|grep -v grep|grep -v defunct`; if [ "x$A" == "x" ]; then echo NOK; else echo OK; fi\' | bash -f -s','main')
    if debug: print 'btVerify1',hcid
    if hcid == 'NOK':
        hcid = getResult('echo \'A=`ps -ef|grep bluetoothd|grep -v grep|grep -v defunct`; if [ "x$A" == "x" ]; then echo NOK; else echo OK; fi\' | bash -f -s','main')
        if debug: print 'btVerify2',hcid
    return hcid

def initVerify():
    tool = isInstalled('anyremote')
    if tool == 'NOK':
        sendMainWindow(20016, _tr("anyRemote not found !\nPlease install it or correct $PATH"))

    tool = isInstalled('sdptool')
    if tool == 'NOK':
         sendMainWindow(20016, _tr("sdptool not found !\nPlease install bluez-util"))

def showDetailsWin(dataList):
    sendMainWindow(20020, dataList)
    
def closeDetailsWin():
    global detailsWin
    try:
        detailsWin.destroy()
        detailsWin = None
    except AttributeError, NameError:
        pass

def closeChooserWin():
    global chooserWin
    try:
        chooserWin.destroy()
        chooserWin = None
    except AttributeError, NameError:
        pass

def showBrowserWin():
    global browserWin
    browserWin = DeviceBrowser()
    browserWin.show()

def closeBrowserWin():
    global browserWin
    try:
        browserWin.destroy()
        browserWin = None
    except AttributeError, NameError:
        pass

def showChkCfgWin():
    global chkCfgWin
    chkCfgWin = CfgChecker()
    chkCfgWin.show()

def closeChkCfgWin():
    global chkCfgWin
    try:
        chkCfgWin.destroy()
        chkCfgWin = None
    except AttributeError, NameError:
        pass

def getAvailableSet():
    global bt_devices

    s = []
    for k, v in bt_devices.iteritems():
        if v[5] == AR_AVAIL:
            s.append(v[0])
    return s

def getDevSet():
    global bt_devices

    s = []
    for k, v in bt_devices.iteritems():
        s.append(v[0])
    return s
    
def browseDevices(force):
    global cmd_array, debug
    
    if ['scan',force] in cmd_array:
        if debug: print 'Skip device scan'
    else:
        queueBT('scan',force)

    return True

def restartBtComm():
    stopBtComm()
    startBtComm()
        
def timerBrowseDevices():
    global cfgReader, quitFlag, browseTimer

    if cfgReader.browseTmout_ > 0 and not quitFlag:
        browseDevices('F')
        browseTimer = QTimer.singleShot(1000*cfgReader.browseTmout_, timerBrowseDevices)

def startBtComm():
    global bt, usepybluez, cfgReader, browseTimer, browseFlag, debug
    if debug: print 'startBtComm'

    if usepybluez == True and bt == None: 
        bt = BtComm(cfgReader.j2meDir_)
        bt.start()
        
        if cfgReader.browseTmout_ > 0:
            # give 5 sec. to thread for start
                browseTimer = QTimer.singleShot(5000, timerBrowseDevices)

def stopBtComm():
    global bt, browseTimer, debug
    if debug: print 'stopBtComm'
    
    try:
        bt.stop()
    except AttributeError, NameError:
        if debug: print 'Exception: bt.stop()'
        pass
    time.sleep(0.5)
    bt = None

def queueBT(tag,address):
    global debug

    if debug: print 'queueBT',cmd_array
    i = len(cmd_array)-1
    if i > 0 and cmd_array[i] == ['scan','']:
        cmd_array.insert(i,[tag,address])
    else:
        cmd_array.append([tag,address]) 

def startFrontend():
    if debug: print 'startFrontend',cmd_array
    global frontEnd
    frontEnd = FrontEnd()
    frontEnd.start()

def stopFrontend():
    global debug, frontEnd
    if debug: print 'stopFrontend'

    # To avoid socket.error: (98, 'Address already in use') 
    # it needs to close client socket first
    killAnyRemote()

    time.sleep(0.5)

    try:
        frontEnd.stop()
    except AttributeError, NameError:
        pass
    
    time.sleep(0.5)   
    frontEnd = None

def usage():
    print 'kanyremote [-h|--help] [-p|--port <port>] [-d|--debug] [-t|--tray] [-y|--ntray] [-e] [-n|--npybluez]'

##################################################################################
#
# Main function
#
##################################################################################

def main():

    global app, systray, debug, port, statusUpdater, cmdToSend, guiMode, usepybluez, usetray, cfgReader, mainWindow
        
    try:
        opts, args = getopt.getopt(sys.argv[1:], "dnyehotp:", ["debug", "expert", "help", "open", "tray", "ntray", "npybluez", "port="])
    except getopt.GetoptError:
        usage()
        sys.exit(2)

    cmdToSend     = ''
    statusUpdater = ''
    guiMode       = 'simple'
    usepybluez    = True
    usetray       = True
    startintray   = False
    systray       = None
     
    app = QApplication(sys.argv)
 	
    for o, a in opts:
        if o in ("-d", "--debug"):
            debug   = True
            guiMode = 'expert'
        if o in ("-e", "--expert"):
            guiMode = 'expert'
        if o in ("-h", "--help"):
            usage()
            sys.exit()
        if o in ("-p", "--port"):
            port = a
        if o in ("-t", "--tray"):
            startintray = True
        if o in ("-y", "--ntray"):
            usetray = False
        if o in ("-n", "--npybluez"):
            usepybluez = False

    if pybluez == False and usepybluez == True:
        print _tr('Install PyBluez first !\nOr run with --npybluez option')
        return
       
    if debug: print 'Use port ' + port
   
    cfg = os.environ.get("HOME")+os.sep+'.anyRemote'
    if not os.path.exists(cfg):
        os.mkdir(cfg)
    
    cfgSet = False
    
    cfgReader = ConfigReader()
    cfgReader.setDefaultConfig()
    if os.path.exists(cfg+os.sep+'anyremote-fe.conf'):
        cfgReader.readConfig()
        cfgSet = True
    else: 
        if os.path.exists('/usr/share/anyremote/cfg-data'):
            cfgSet = True
            cfgReader.cfgDirs.append('/usr/share/anyremote/cfg-data')
        elif os.path.exists('/usr/local/share/anyremote/cfg-data'):
            cfgSet = True
            cfgReader.cfgDirs.append('/usr/local/share/anyremote/cfg-data/')
        # quick fix for ubuntu
        elif os.path.exists('/etc/anyremote/cfg-data'):
            cfgSet = 1
            cfgReader.cfgDirs.append('/etc/anyremote/cfg-data')
            
        cfgReader.j2meDir_ = getJ2MEPath()
        
        if cfgSet == 1:
           cfgReader.setAutoStartFile()
    
    # add to cache default fallback icon
    getPixmap("document-open")
    
    app.setWindowIcon(QIcon(getPixmap("kanyremote_small")))
        
    mainWindow = kAnyRemote(cfgSet)
    
    if cfgReader.checkJ2MEUpdate_:
        if debug: print 'Check J2ME client updates at web'
        jv = JCVerifier(False)
        jv.start()
    
    if startintray:
        mainWindow.isShown = 0
    else:
        mainWindow.isShown = 1
        mainWindow.show()
    
    initVerify()

    systray = None
    if usetray:
        
        systray = QSystemTrayIcon(mainWindow)
	
        setTrayIcon("kanyremote_off")
         
        mainWindow.trayAboutAction   = QAction(loadIcon("help-about",      "help"),_tr("About"), mainWindow)
        mainWindow.trayStartAction   = QAction(loadIcon("system-run",      "run"), _tr("Start"), mainWindow)
        mainWindow.trayStopAction    = QAction(loadIcon("dialog-close",    "stop"),_tr("Stop"),  mainWindow)
        mainWindow.trayMinMaxAction  = QAction(_tr("Minimize")+'/'+_tr("Restore"),  mainWindow)
        mainWindow.trayQuitAction    = QAction(loadIcon("application-exit","exit"),_tr("Quit"),  mainWindow)
        
        mainWindow.connect(mainWindow.trayAboutAction,  SIGNAL("triggered()"), mainWindow.helpAbout)
        mainWindow.connect(mainWindow.trayStartAction,  SIGNAL("triggered()"), mainWindow.runAction)
        mainWindow.connect(mainWindow.trayStopAction,   SIGNAL("triggered()"), mainWindow.stopAction)
        mainWindow.connect(mainWindow.trayMinMaxAction, SIGNAL("triggered()"), mainWindow.minMaxAction)
        mainWindow.connect(mainWindow.trayQuitAction,   SIGNAL("triggered()"), mainWindow.fileExit)

        trayMenu = QMenu()
        trayMenu.addAction(mainWindow.trayAboutAction)
        trayMenu.addAction(mainWindow.trayStartAction)
        trayMenu.addAction(mainWindow.trayStopAction)
        trayMenu.addAction(mainWindow.trayMinMaxAction)
        trayMenu.addAction(mainWindow.trayQuitAction)
	
        systray.setContextMenu(trayMenu)
        app.connect(systray, SIGNAL("quitSelected()"), mainWindow.fileExit)
        
        systray.show()

    app.connect(app, SIGNAL("lastWindowClosed()"), app, SLOT("quit()"))

    mainWindow.setStatusStopped()

    startFrontend()
    
    mainWindow.autoStartBackend()
    
    app.exec_()

if __name__ == "__main__":
    global debug, port, cmdToSend, appData, bt_devices, quitFlag, jup, cmd_array, mainWindow, browserWin, chooserWin, chkCfgWin, detailsWin, bt, pbarTimer, pbar

    port       = '5050'
    debug      = False
    appData    = dict()
    bt_devices = dict()
    cmdToSend  = ''
    quitFlag   = False
    cmd_array  = [] 
    mainWindow = None 
    detailsWin = None    
    browserWin = None    
    chooserWin = None    
    chkCfgWin  = None    
    bt         = None
    pbarTimer  = None
    pbar       = None
    jup        = None
    
    main()

