#!/usr/bin/env python

"""
v 5.4

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

Copyright (C) 2007,2008 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 locale
import os
import re
import signal
import socket
import SocketServer
import sys
import sys
import thread
import threading
import time
from sets import Set

#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 !!!'
   quit()

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(":")

#langs += ["ru_RU"]
#print 'langs',langs

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.gettext

try:
    from qt import *
except ImportError:
   print 'Install PyQT first !!!'
   quit()

try:
   from kdecore import KAboutData, KApplication, KCmdLineArgs, KIcon, KIconLoader
   from kdeui import KAboutApplication, KSystemTray, KTextEdit
   from kfile import KURLRequester
   from dcopexport import DCOPExObj
except ImportError:
   print 'Install PyKDE first !!!'
   quit()

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')

signal.signal(signal.SIGINT, signal.SIG_DFL)

##################################################################################
#
# Blink Icon class
#
##################################################################################

class BlinkThread(QThread):
        def __init__(self,receiver):
            QThread.__init__(self) 
	    self.receiver = receiver

        def run(self):
	   sendEvent(self.receiver,20001," ") 
	   time.sleep(0.2)
	   sendEvent(self.receiver,20002," ") 
	   
##################################################################################
#
# Reader of cfg. files
#
##################################################################################
class CfgFileReader(threading.Thread):

    def __init__(self, receiver, cReader):
	threading.Thread.__init__(self)
	self.receiver = receiver
	self.cfgDirs  = cReader.cfgDirs
	self.all      = cReader.showAll_
	self.apps     = cReader.showApps_
	self.cust     = cReader.showCustom_
	self.ex       = cReader.showExamples_ 
	self.at       = cReader.showAt_
	self.srv      = cReader.showSrv_   
	self.bm       = cReader.showBm_   

    def run(self):
        global debug, appData
	
	time.sleep(1)
	
	if debug: print 'CfgFileReader.run'
	
        appData.clear()
        
	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]+$")

	for cfgDir in self.cfgDirs:
	    
	    if cfgDir == '':
	        continue
	    if debug: 
	        print 'Collect files in '+cfgDir
	    
	    self.idx = 0
	    if os.path.isfile(cfgDir):
	        self.processOneFile(cfgDir)
	    else:
	        for root, dirs, files in os.walk(cfgDir):
                
	            for cfgFile in files:
	    	        self.processOneFile(root + os.sep + cfgFile)
			
	# start StatusUpdater if needed
	sendEvent(self.receiver, 20007, '')
	    
    def processOneFile(self,cfgFile):
        global debug, iconsK, appData, lastCfgFile
	
        fd = None
        try:
	    fd = open(cfgFile,'r')
        except IOError:
            pass
            
	if fd:
	    aName    = None
	    aInst    = ''
	    aRun     = ''
	    aIcon    = ''
	    aType    = None
	    aDesc    = ''
	    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)
		
		    # obsolete; changed to GuiAppDesc
	    	    p = re.search("^[^a-zA-Z0-9]*GuiDescription[^=]*=(.+)$", line)
	    	    if p != None:
	    		aDesc = 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 aBemused == 1:
		aMode = 'Bemused'
	    elif aDevice == 'a':
		aMode = 'AT'
	    	
	    if aName == '':
	    	aName = os.path.basename(cfgFile)
	    	
	    if aInst == '':
	    	isInst = AR_NOINFO
	    else:
	    	isInst = isInstalled(aInst)

	    show = 1
	    status = ''
	    if isInst == 'OK':
	    	status = AR_AVAIL
	    elif isInst == 'NOK':
	        status = AR_NOTAVAIL
		if not self.all:
	            show = 0
	    
	    if not self.all:
	    	if aMode == 'AT' and not self.at:
	    	    show = 0
	    	elif aMode == 'Server' and not self.srv:
	    	    show = 0
	        elif aMode == 'Bemused' and not self.bm:
	    	    show = 0
	    
	        if aType == 'Application' and not self.apps:
	            show = 0
	        elif aType == 'Custom' and not self.cust:
	            show = 0
	        elif aType == 'Example' and not self.ex :
	            show = 0
	        elif aType == '':
	            show = 0
		    
            if show == 1:
		if debug: print 'Proceed '+aName
	
	    	if aIcon == '':
	    	    aIcon = 'filenew.png'
	    
		pbuf = iconsK.loadIcon(aIcon, KIcon.Small)
		
                isRun = AR_NOINFO
	    	if aRun != '':
	    	    isRun  = getResult(aRun,'reader')

		appData[self.idx] = [aName, pbuf, aInst, aRun, isRun, cfgFile, status, _tr(aMode), _tr(aType), aDesc]
			
		self.idx = self.idx + 1
		
	    else:
		if debug: print 'Skip '+aName
	    	 
	    fd.close()
	    
##################################################################################
#
# Device Browser
#
##################################################################################
class DeviceBrowser(QMainWindow):

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

        if not name:
            self.setName("DeviceBrowser")

        self.setCentralWidget(QWidget(self,"qt_central_widget"))
        DeviceBrowserLayout = QGridLayout(self.centralWidget(),1,1,11,6,"DeviceBrowserLayout")

        self.treeview = QListView(self.centralWidget(),"treeview")
        self.treeview.addColumn(_tr("Name       "))
        self.treeview.addColumn(_tr("Device Name"))
        self.treeview.addColumn(_tr("Address          "))
        self.treeview.addColumn(_tr("Status       "))

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

        self.scanAction    = QAction(QIconSet(iconsK.loadIcon("filefind",  KIcon.Small)),  _tr("Scan for devices"), QKeySequence(),self)
        self.detailsAction = QAction(QIconSet(iconsK.loadIcon("configure", KIcon.Small)),  _tr("Details"), QKeySequence(),self)
        self.deleteAction  = QAction(QIconSet(iconsK.loadIcon("editdelete", KIcon.Small)), _tr('Delete'), QKeySequence(),self)
        self.closeAction   = QAction(QIconSet(iconsK.loadIcon("fileclose",  KIcon.Small)), _tr('Close'), QKeySequence(),self)
        
        self.MenuBar = QMenuBar(self,"MenuBar")

        self.fileMenu = QPopupMenu(self)
        self.scanAction.addTo   (self.fileMenu)
        self.detailsAction.addTo(self.fileMenu)
        self.deleteAction.addTo (self.fileMenu)
        self.closeAction.addTo  (self.fileMenu)
        self.MenuBar.insertItem(QString(""),self.fileMenu,1)

        self.languageChange()

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

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

	self.connect(self.treeview,SIGNAL('doubleClicked(QListViewItem*, const QPoint&, int)'), self.listDClicked)
	
	self.treeview.setColumnWidthMode (0,QListView.Maximum) 
	self.treeview.setColumnWidthMode (1,QListView.Maximum) 
	self.treeview.setColumnWidthMode (2,QListView.Maximum) 
	self.treeview.setColumnWidthMode (3,QListView.Maximum) 
	
	self.treeview.setMultiSelection(False)
	self.treeview.setSortColumn(0)
	
	self.populateDeviceList()

    def languageChange(self):
        self.setCaption(_tr("kAnyRemote device browser"))
        self.treeview.header().setLabel(0,_tr("Name"))
        self.treeview.header().setLabel(1,_tr("Device Name"))
        self.treeview.header().setLabel(2,_tr("Address"))
        self.treeview.header().setLabel(3,_tr("Status"))
        self.treeview.clear()
        item = QListViewItem(self.treeview,None)

        self.scanAction.setText(_tr("Scan for devices"))
        self.scanAction.setMenuText(_tr("Scan for devices"))
        self.detailsAction.setText(_tr("Details"))
        self.detailsAction.setMenuText(_tr("Details"))
        self.deleteAction.setText(_tr('Delete'))
        self.deleteAction.setMenuText(_tr('Delete'))
        self.closeAction.setText(_tr('Close'))
        self.closeAction.setMenuText(_tr('Close'))
        self.closeAction.setAccel(QString.null)
        if self.MenuBar.findItem(1):
            self.MenuBar.findItem(1).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 = QListViewItem(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][4])

    def scan(self):
        browseDevices()

    def details(self):
        global bt_devices
	
	item = self.treeview.selectedItem()
    	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],False)

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

    def deleteDev(self):
        global bt_devices
	
	item = self.treeview.selectedItem()
	self.treeview.takeItem(item)

    def closeAct(self):
        self.hide()

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

##################################################################################
#
# Device Details
#
##################################################################################
class DeviceDetail(QMainWindow):
    def __init__(self, ba, m, n, act, is_new, jDir, parent = None,name = None,fl = 0):
        QMainWindow.__init__(self,parent,name,fl)
        self.statusBar()

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

        if not name:
            self.setName("DeviceDetail")

        self.setCentralWidget(QWidget(self,"qt_central_widget"))
        DeviceDetailLayout = QGridLayout(self.centralWidget(),1,1,11,6,"DeviceDetailLayout")

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

        self.btAddress = QLabel(self.centralWidget(),"btAddress")
        DeviceDetailLayout.addMultiCellWidget(self.btAddress,0,0,3,4)
	
        self.btAddressValue = QLabel(self.centralWidget(),"btAddressValue")
        DeviceDetailLayout.addMultiCellWidget(self.btAddressValue,0,0,5,6)


        self.specifyName = QLabel(self.centralWidget(),"specifyName")
        DeviceDetailLayout.addWidget(self.specifyName,1,0)
	
        self.devName = QLineEdit(self.centralWidget(),"devName")
        DeviceDetailLayout.addMultiCellWidget(self.devName,1,1,1,6)

        self.runWhen = QCheckBox(self.centralWidget(),"runWhen")
        DeviceDetailLayout.addMultiCellWidget(self.runWhen,2,2,0,6)
	QToolTip.add(self.runWhen, _tr('anyRemote will start only if no other instances of anyRemote are running'));
	
        self.fileWhen = QLineEdit(self.centralWidget(),"fileWhen")
        DeviceDetailLayout.addMultiCellWidget(self.fileWhen,3,3,0,5)
        self.choose = QPushButton(self.centralWidget(),"choose")
        DeviceDetailLayout.addWidget(self.choose,3,6)

	
        spacer1 = QSpacerItem(20,16,QSizePolicy.Minimum,QSizePolicy.Expanding)
        DeviceDetailLayout.addMultiCell(spacer1,4,4,2,3)

	self.kSeparator1 = QFrame(self.centralWidget(),"kSeparator1")
        self.kSeparator1.setFrameShape(QFrame.HLine)
        self.kSeparator1.setFrameShadow(QFrame.Sunken)
        self.kSeparator1.setFrameShape(QFrame.HLine)
        DeviceDetailLayout.addMultiCellWidget(self.kSeparator1,5,5,0,6)

        self.uploadjava = QPushButton(self.centralWidget(),"uploadjava")
        DeviceDetailLayout.addWidget(self.uploadjava,6,0)
	
        self.iSet = QLabel(self.centralWidget(),"iSet")
        DeviceDetailLayout.addMultiCellWidget(self.iSet,6,6,1,2)
	
	
        spacer2 = QSpacerItem(40,20,QSizePolicy.Expanding,QSizePolicy.Minimum)
        DeviceDetailLayout.addItem(spacer2,6,2)
	
        self.sz16 = QCheckBox(self.centralWidget(),"sz16")
        DeviceDetailLayout.addWidget(self.sz16,6,3)
	self.sz16.setChecked(True)

        self.sz32 = QCheckBox(self.centralWidget(),"sz32")
        DeviceDetailLayout.addWidget(self.sz32,6,4)

        self.sz64 = QCheckBox(self.centralWidget(),"sz64")
        DeviceDetailLayout.addWidget(self.sz64,6,5)
	

        self.uplJad = QCheckBox(self.centralWidget(),"uplJad")
        DeviceDetailLayout.addMultiCellWidget(self.uplJad,7,7,0,1)
	QToolTip.add(self.uplJad, _tr('Can be useful for Samsung phones'));

        self.javaSize = QCheckBox(self.centralWidget(),"javaSize")
        DeviceDetailLayout.addMultiCellWidget(self.javaSize,7,7,3,6)
	QToolTip.add(self.javaSize, _tr('16x16 and 64x64 title icons are available'));
	
        self.ping = QPushButton(self.centralWidget(),"ping")
        DeviceDetailLayout.addWidget(self.ping,8,0)
        self.testat = QPushButton(self.centralWidget(),"testat")
        DeviceDetailLayout.addWidget(self.testat,8,1)
	
        spacer2 = QSpacerItem(40,20,QSizePolicy.Expanding,QSizePolicy.Minimum)
        DeviceDetailLayout.addItem(spacer2,8,2)

        self.close = QPushButton(self.centralWidget(),"Close")
        DeviceDetailLayout.addWidget(self.close,8,5)
        self.ok = QPushButton(self.centralWidget(),"Ok")
        DeviceDetailLayout.addWidget(self.ok,8,6)

        self.languageChange()

        #self.resize(QSize(200,230))
	#.expandedTo(self.minimumSizeHint()))
        self.clearWState(Qt.WState_Polished)
        
	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.uploadjava, 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.sz16,     SIGNAL("toggled(bool)"),self.clicked_sz16)
	self.connect(self.sz32,     SIGNAL("toggled(bool)"),self.clicked_sz32)
	self.connect(self.sz64,     SIGNAL("toggled(bool)"),self.clicked_sz64)
	self.connect(self.javaSize, SIGNAL("toggled(bool)"),self.clicked_bti)

	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): 
	    print 'nor exists',self.midletDir
	    self.uploadjava.setEnabled(False)
	    self.javaSize.setEnabled(False)
	    self.uplJad.setEnabled(False)
	    QToolTip.add(self.uploadjava, _tr('It needs to install anyremote-J2ME-client package first'));

 	bt = btVerify(self,False)
	if bt == 'NOK': 
	    print 'DeviceDetail: Bluetooth not active'
	    
	    self.ping.setEnabled(False)
	    self.testat.setEnabled(False)
	    self.uploadjava.setEnabled(False)
	    self.javaSize.setEnabled(False)
	    QToolTip.add(self.ping, _tr('Bluetooth service is not active'));
	    QToolTip.add(self.testat, _tr('Bluetooth service is not active'));

    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_sz16(self,w):
        if not self.sz16.isChecked():
           self.sz16.setChecked(True)   # do not allow to reset
           self.sz32.setChecked(False)
           self.sz64.setChecked(False)

    def clicked_sz32(self,w):
        if self.sz32.isChecked():
           self.sz16.setChecked(True)
        else:
           self.sz64.setChecked(False)

    def clicked_sz64(self,w):
        if self.sz64.isChecked():
           self.sz16.setChecked(True)
           self.sz32.setChecked(True)
           self.javaSize.setChecked(True)

    def clicked_bti(self,w):
        if not self.javaSize.isChecked():
           self.sz64.setChecked(False)
    
    def chooseAction(self):
    	global chooserWin
	chooserWin = Chooser()
	chooserWin.show()

    def close(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[3]:
	            row[3] = cf
		
		self.sendReRead()
		self.hide()
		return

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

	self.sendReRead()
        self.hide()
    
    def testatAction(self):
        global debug
	if debug: print 'Queue test AT'
	    
	stopPBar() 
	pbar = runPBar(AR_WAIT_OPS,30)
	queueBT('test_at',self.btAddr)
    
    def uploadjAction(self):
        global debug
	if debug: print 'Queue push request'
	
	sz = '16'
	if self.sz32.isChecked():
	   sz = '32'
	if self.sz64.isChecked():
	   sz = '64'
	if self.javaSize.isChecked():
	   sz = sz+'b'
	   
	push = 'pushjar'
	if self.uplJad.isChecked():
	    push = 'pushjad'
	   
	stopPBar() 
	pbar = runPBar(AR_WAIT_OPS,20)
	queueBT(push+sz,self.btAddr)
    
    def pingAction(self):
        global debug
	if debug: print 'Queue ping request'

	stopPBar() 
	pbar = runPBar(_tr('Wait ping results'),20)
	queueBT('ping',self.btAddr)
	
    def setStatustext(self,text):
        global debug
        if debug: print 'DeviceDetail.setStatustext ' + text
        self.statusBar().clear()
        self.statusBar().message(text)

    def customEvent(self,event):
        if event.type() == 31000:
	    self.cfile = event.data()
	    self.fileWhen.setText(self.cfile)

    def languageChange(self):
        self.setCaption(_tr("Device Parameters"))
        self.deviceNameValue.setText(QString.null)
        self.btAddress.setText(_tr("BT address:"))
        self.btAddressValue.setText(QString.null)
        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.javaSize.setText(_tr("use big title icon"))
        self.uplJad.setText(_tr("Also upload JAD"))
        self.sz16.setText("16x16")
        self.sz32.setText("32x32")
        self.sz64.setText("64x64")
        self.choose.setText(_tr('Choose'))
        self.ping.setText(_tr("Ping"))
        self.uploadjava.setText(_tr("Upload Java"))
        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,name = None,fl = 0):
    
        global cfgReader
        
        QMainWindow.__init__(self,parent,name,fl)

        if not name: self.setName("CfgChecker")

        self.setCentralWidget(QWidget(self,"qt_central_widget"))
        CfgCheckerLayout = QGridLayout(self.centralWidget(),1,1,11,6,"CfgCheckerLayout")

        self.treeview = QListView(self.centralWidget(),"treeview")
        self.treeview.addColumn(_tr("Package"))
        self.treeview.addColumn(_tr("Status"))

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

        self.closeAction   = QAction(QIconSet(iconsK.loadIcon("fileclose", KIcon.Small)), _tr("Close"), QKeySequence(),self)

        self.MenuBar = QMenuBar(self,"MenuBar")

        self.fileMenu = QPopupMenu(self)
        self.closeAction.addTo  (self.fileMenu)
        self.MenuBar.insertItem(QString(""),self.fileMenu,1)

        self.languageChange()

        self.resize(QSize(450,250).expandedTo(self.minimumSizeHint()))
        self.clearWState(Qt.WState_Polished)

        self.connect(self.closeAction,  SIGNAL("activated()"),self.closeAct)
	
	self.treeview.setColumnWidthMode (0,QListView.Maximum) 
	self.treeview.setColumnWidthMode (1,QListView.Maximum) 
	
	self.treeview.setMultiSelection(False)
	self.treeview.setSortColumn(0)
        self.treeview.setRootIsDecorated(True)
	
    	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()
 	ajs = AR_INSTALLED
        if jDir == '':
	    ajs = AR_NOTINSTALLED

        ahs = isInstalled('anyremote2html')
        if ahs == 'NOK':
	    ahs = AR_NOTINSTALLED
        else:
            ahs = AR_INSTALLED
    
        lvi = QListViewItem(self.treeview)
        lvi.setText(0,"anyRemote")       
        lvi.setText(1,ars)
	
        lvi = QListViewItem(self.treeview)
        lvi.setText(0,"Bluez utilities")       
        lvi.setText(1,bus)

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

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

	if jDir != cfgReader.javaDir_: #and jDir != '':
           lvi.setOpen(True)
           lvi2 = QListViewItem(lvi)
           lvi2.setText(0,_tr('Warning:'))       
           lvi2.setText(1,_tr('Installation directory of anyremote-J2ME-client not specified in current setup configuration !'))

        lvi = QListViewItem(self.treeview)
        lvi.setText(0,"anyremote2html")       
        lvi.setText(1,ahs)
 
    def languageChange(self):
        self.setCaption(_tr("kAnyRemote configuration checker"))
        self.treeview.header().setLabel(0,_tr("Package"))
        self.treeview.header().setLabel(1,_tr("Status"))
        self.treeview.clear()
        item = QListViewItem(self.treeview,None)

        self.closeAction.setText(_tr('Close'))
        self.closeAction.setMenuText(_tr('Close'))
        self.closeAction.setAccel(QString.null)
        if self.MenuBar.findItem(1):
            self.MenuBar.findItem(1).setText(_tr("File"))
	
	self.cfgChkWin = None
	self.selected = None

    def closeAct(self):
        self.hide()

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

class Chooser(QMainWindow):

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

        if not name:
            self.setName("Choose application")

        self.setCentralWidget(QWidget(self,"qt_central_widget"))
        Form1Layout = QGridLayout(self.centralWidget(),1,1,11,6,"Form1Layout")

        self.listView1 = QListView(self.centralWidget(),"listView1")
        self.listView1.addColumn(_tr("Application"))
        self.listView1.addColumn(_tr("Mode"))
        self.listView1.addColumn("F")

	self.listView1.setColumnWidthMode (0,QListView.Maximum) 
	self.listView1.setColumnWidthMode (1,QListView.Maximum) 
	self.listView1.setColumnWidthMode (2,QListView.Manual) 
	
	self.listView1.setMultiSelection(False)
	self.listView1.setSortColumn(0)
	self.listView1.hideColumn(2)
	
        Form1Layout.addMultiCellWidget(self.listView1,0,0,0,1)

        self.cancel = QPushButton(self.centralWidget(),"cancel")
        Form1Layout.addWidget(self.cancel,1,1)

        self.ok = QPushButton(self.centralWidget(),"ok")

        Form1Layout.addWidget(self.ok,1,0)

        self.languageChange()

        self.resize(QSize(350,400).expandedTo(self.minimumSizeHint()))
        self.clearWState(Qt.WState_Polished)

	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 = QListViewItem(self.listView1)
	    lvi.setPixmap(0,v[1])
	    lvi.setText(0,v[0])	  
	    lvi.setText(1,v[7])
	    lvi.setText(2,str(k))
	    	
    def cancelAction(self):
        self.hide()

    def okAction(self):
        global appData

	item = self.listView1.selectedItem()
    	if item == None:
	    return

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

    def languageChange(self):
        self.setCaption(_tr("Choose application"))
        self.listView1.header().setLabel(0,_tr("Application"))
        self.listView1.header().setLabel(1,_tr("Mode"))
        self.listView1.clear()
        item = QListViewItem(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, '', steps)

	self.setCancelButton(None)
	self.setAutoReset(True)
	self.setAutoClose(False)
	self.show()
	

def runPBar(text,time):
    global pbar, pbarTimer

    pbar = PBar(text,time)
    timerPBar()

def stopPBar():
    global pbar, pbarTimer

    try:
        pbarTimer.stop()
    except AttributeError:
        pass
	
    try:
        pbar.cancel()
	pbar = None
    except AttributeError, NameError:
        pass
	
def writePBar(txt):
    global pbar
    try:
        pbar.setLabelText(txt)
    except AttributeError, NameError:
        pass
	
def timerPBar():
    global pbar, pbarTimer

    if not quitFlag:
    	try:
    	    pbar.setProgress(pbar.progress()+1)
    	except AttributeError, NameError:
    	    return
    	pbarTimer = QTimer.singleShot(1000,timerPBar)
	
##################################################################################
#
# 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()
	    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
        
	if debug:
            print 'set for',address,status

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

    	        return

    def doScan(self):
	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)
	
	    if addr not in existing:
	        showDetailsWin(addr, name, name, '', True)
	    else:
		if addr in availSet:
		    availSet.discard(addr)
		else:
		    self.setStatus(addr,AR_AVAIL)
	    
	for rest in availSet:
	    self.setStatus(rest, '')
	
	if debug:
	    print 'BtComm: verify done'

    def doPing(self, data):
	global debug, dwin
	if debug: print 'BtComm: ping device'
	
	dwin.setStatustext('')
	writePBar(AR_CONN_DEV)
	
	os.system('killall -9 hcitool')
	if debug: print 'hcitool name '+data
	ret = getResult('hcitool name '+data,'browser')
	
	stopPBar()
	if (ret == ''):
	    dwin.setStatustext(_tr('Ping failed !'))
	else:
	    dwin.setStatustext(_tr('Ping OK !'))

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

	dwin.setStatustext('')
	stopPBar()   
	
	if not os.path.exists(self.midletDir):       
	    dwin.setStatustext(_tr('Can not find anyremote-J2ME-client installation !'))
	    return
	
	midlet = 'anyRemote-' + size + '.jar'
	path = self.midletDir + os.sep + midlet
	if not os.path.isfile(path):
	    dwin.setStatustext(_tr('Can not find java midlet ('+midlet+_tr(') to upload !')))
	    return
		     
	sender = ''    
	if (isInstalled('gnome-obex-send') == 'OK'):
	    sender = 'gnome-obex-send -d '+data
	elif (isInstalled('bluetooth-sendto') == 'OK'):
	    sender = 'bluetooth-sendto --dest='+data
	elif (isInstalled('kbtobexclient') == 'OK'):
	    sender = 'kbtobexclient'
	else:
	    dwin.setStatustext(_tr('None of gnome-obex-send, bluetooth-sendto and kbtobexclient are installed !'))
	    return
	
	ret = getResult(sender+' '+path+' &','browser')
	
	if usejad:
	    jad = 'anyRemote-' + size + '.jad'
	    path = self.midletDir + os.sep + jad
	    if not os.path.isfile(path):
	        dwin.setStatustext(_tr('Can not find JAD file ('+jad+_tr(') to upload !')))
	        return
	    
	    ret = getResult(sender+' '+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'):
	            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, dwin
	if debug: print 'BtComm: doAT'
	    
	dwin.setStatustext('')
	writePBar(AR_CONN_DEV)	
    	port = self.getSerialPort(data)
	if debug: print 'BtComm: port',port
        
	if port == None:
	    dwin.setStatustext(_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)
		print d
		stopPBar()
	        if d.startswith('(111,'):
		    dwin.setStatustext(_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)')
		
            dwin.setStatustext(status)
            sock.close()

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

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

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

    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
		        sendEvent(self.receiver, 20006, [k,v[6],isRun])	

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

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

    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'

    	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:

    		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
    	
    	    sendEvent(self.receiver,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:
		        sendEvent(self.receiver,10000,data)
    	    	
    	    	    if not data: 
    	    		if debug: print 'FrontEnd anyRemote die?'
    	    	    
		        if self.isRun:
		            sendEvent(self.receiver,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' 
	    sendEvent(self.receiver,20012,'')  
    	    conn.close()

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

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

        if not name: self.setName("Edit configuration file")

        self.setCentralWidget(QWidget(self,"qt_central_widget"))
        EditWinLayout = QGridLayout(self.centralWidget(),1,1,11,6,"EditWinLayout")
       

        self.textEdit1 = KTextEdit(self.centralWidget(),"textEdit1")

        EditWinLayout.addMultiCellWidget(self.textEdit1,0,0,0,1)

        self.saveEditor   = QAction(QIconSet(iconsK.loadIcon("filesave",  KIcon.Small)), _tr("Save"),  QKeySequence(),self)
        self.saveAsEditor = QAction(QIconSet(iconsK.loadIcon("filesaveas",KIcon.Small)), _tr("Save As"),QKeySequence(),self)
        self.closeEditor  = QAction(QIconSet(iconsK.loadIcon("fileclose", KIcon.Small)), _tr("Close"),  QKeySequence(),self)
	
        self.Menu = QMenuBar(self,"Menu")
        self.fileMenu = QPopupMenu(self)

        self.saveEditor.addTo(self.fileMenu)
        self.saveAsEditor.addTo(self.fileMenu)
        self.closeEditor.addTo(self.fileMenu)
	self.Menu.insertItem(QString(""),self.fileMenu,1)

        self.languageChange()

        self.resize(QSize(550,500).expandedTo(self.minimumSizeHint()))
        self.clearWState(Qt.WState_Polished)
	
        self.connect (self.saveEditor,  SIGNAL ("activated()"), self.saveFile)
        self.connect (self.saveAsEditor,SIGNAL ("activated()"), self.saveAs)
        self.connect (self.closeEditor, SIGNAL ("activated()"), 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.setCaption(_tr("Edit configuration file"))
        self.closeEditor.setText(_tr("Close"))
        self.saveEditor.setText(_tr("Save"))
        self.saveEditor.setAccel(QKeySequence(_tr("Ctrl+S")))
        self.saveAsEditor.setText(_tr("Save As"))
        if self.Menu.findItem(1):
            self.Menu.findItem(1).setText(_tr("File"))


    def saveFile(self):
	try:
	    f=open(self.eFile, 'w')
	    if f:
	        f.write(str(self.textEdit1.text()))
	        f.close()
                self.deleteLater()   

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

class Preferences(QMainWindow):
    def __init__(self,mainWin,cfgReader,parent = None,name = None,fl = 0):
        QMainWindow.__init__(self,parent,name,fl)

        if not name:
            self.setName("Preferences")

        self.setMinimumSize(QSize(709,429))

        self.setCentralWidget(QWidget(self,"qt_central_widget"))
        PreferencesLayout = QGridLayout(self.centralWidget(),1,1,11,6,"PreferencesLayout")

        self.textLabel1 = QLabel(self.centralWidget(),"textLabel1")
        self.textLabel1.setAlignment(QLabel.AlignCenter)
        self.textLabel1.setIndent(-2)
        PreferencesLayout.addMultiCellWidget(self.textLabel1,0,0,1,7)
 	
        self.dirView = QListView(self.centralWidget(),"dirView")
        self.dirView.addColumn(_tr("Directories"))
        self.dirView.header().setClickEnabled(0,self.dirView.header().count() - 1)
	self.dirView.setResizeMode(QListView.LastColumn)
        PreferencesLayout.addMultiCellWidget(self.dirView,1,1,0,8)

	self.addButton = QPushButton(self.centralWidget(),"addButton")
        PreferencesLayout.addWidget(self.addButton,2,0)
        self.delButton = QPushButton(self.centralWidget(),"delButton")
        PreferencesLayout.addWidget(self.delButton,2,1)

        ###
        self.jdirLabel = QLabel(self.centralWidget(),"jdirLabel")
        PreferencesLayout.addMultiCellWidget(self.jdirLabel,3,3,0,1)
        self.javaDir = QLineEdit(self.centralWidget(),"javaDir")
        PreferencesLayout.addMultiCellWidget(self.javaDir,3,3,2,7)
        self.jDir = QPushButton(self.centralWidget(),"jDir")
        PreferencesLayout.addWidget(self.jDir,3,8)
	
        ###
        self.line10 = QFrame(self.centralWidget(),"line10")
        self.line10.setFrameShape(QFrame.HLine)
        self.line10.setFrameShadow(QFrame.Sunken)
        self.line10.setFrameShape(QFrame.HLine)
        PreferencesLayout.addMultiCellWidget(self.line10,4,4,0,8)

        self.textLabel3 = QLabel(self.centralWidget(),"textLabel3")
        PreferencesLayout.addMultiCellWidget(self.textLabel3,5,5,0,1)
        self.appl = QCheckBox(self.centralWidget(),"appl")
        PreferencesLayout.addMultiCellWidget(self.appl,5,5,2,4)
        self.custom = QCheckBox(self.centralWidget(),"custom")
        PreferencesLayout.addWidget(self.custom,5,5)
        self.examples = QCheckBox(self.centralWidget(),"examples")
        PreferencesLayout.addMultiCellWidget(self.examples,5,5,6,8)
	
        self.srv = QCheckBox(self.centralWidget(),"srv")
        PreferencesLayout.addWidget(self.srv,6,5)
        self.bem = QCheckBox(self.centralWidget(),"bem")
        PreferencesLayout.addMultiCellWidget(self.bem,6,6,6,8)
        self.at = QCheckBox(self.centralWidget(),"at")
        PreferencesLayout.addMultiCellWidget(self.at,6,6,2,4)
        self.all = QCheckBox(self.centralWidget(),"all")
        PreferencesLayout.addMultiCellWidget(self.all,6,6,0,1)
	
        self.line12 = QFrame(self.centralWidget(),"line12")
        self.line12.setFrameShape(QFrame.HLine)
        self.line12.setFrameShadow(QFrame.Sunken)
        self.line12.setFrameShape(QFrame.HLine)
        PreferencesLayout.addMultiCellWidget(self.line12,7,7,0,8)
	
        self.textLabel4 = QLabel(self.centralWidget(),"textLabel4")
        PreferencesLayout.addMultiCellWidget(self.textLabel4,8,8,0,2)
        self.tmout = QLineEdit(self.centralWidget(),"tmout")
        PreferencesLayout.addWidget(self.tmout,8,3)
	QToolTip.add(self.tmout, _tr('Empty field means no update'))
        self.textLabel5 = QLabel(self.centralWidget(),"textLabel5")
        PreferencesLayout.addWidget(self.textLabel5,8,4)
 	self.autoGnome = QCheckBox(self.centralWidget(),"autoGnome")
        PreferencesLayout.addWidget(self.autoGnome,8,6)
        self.textLabel6 = QLabel(self.centralWidget(),"textLabel6")
        PreferencesLayout.addWidget(self.textLabel6,8,5)
        self.autoKDE = QCheckBox(self.centralWidget(),"autoKDE")
        PreferencesLayout.addMultiCellWidget(self.autoKDE,8,8,7,8)

	self.line15 = QFrame(self.centralWidget(),"line15")
        self.line15.setFrameShape(QFrame.HLine)
        self.line15.setFrameShadow(QFrame.Sunken)
        self.line15.setFrameShape(QFrame.HLine)
        PreferencesLayout.addMultiCellWidget(self.line15,9,9,0,8)
		
        self.textLabel7 = QLabel(self.centralWidget(),"textLabel7")
        PreferencesLayout.addMultiCellWidget(self.textLabel7,10,10,0,4)
        self.deviceOver = QLineEdit(self.centralWidget(),"deviceOver")
        PreferencesLayout.addWidget(self.deviceOver,10,5)
        self.auto_reconnect = QCheckBox(self.centralWidget(),"auto_reconnect")
        PreferencesLayout.addMultiCellWidget(self.auto_reconnect,10,10,6,8)
	
        self.runWeb = QCheckBox(self.centralWidget(),"runWeb")
        PreferencesLayout.addMultiCellWidget(self.runWeb,11,11,0,4)
        self.webParams1 = QLineEdit(self.centralWidget(),"webParams")
        self.webParams1.setReadOnly(True);
        PreferencesLayout.addMultiCellWidget(self.webParams1,11,11,5,5)
        self.webParams = QLineEdit(self.centralWidget(),"webParams")
        PreferencesLayout.addMultiCellWidget(self.webParams,11,11,6,6)

        self.line11 = QFrame(self.centralWidget(),"line11")
        self.line11.setFrameShape(QFrame.HLine)
        self.line11.setFrameShadow(QFrame.Sunken)
        self.line11.setFrameShape(QFrame.HLine)
        PreferencesLayout.addMultiCellWidget(self.line11,12,12,0,8)

        self.labelRunWhen = QLabel(self.centralWidget(),"labelRunWhen")
        PreferencesLayout.addMultiCellWidget(self.labelRunWhen,13,13,0,4)
        self.browseTmout = QLineEdit(self.centralWidget(),"browseTmout")
        PreferencesLayout.addWidget(self.browseTmout,13,5)
	QToolTip.add(self.browseTmout, _tr('Empty field means no update. Beware: Java client could fail to connect to anyRemote when browsing is in process'));

        self.lineBr = QFrame(self.centralWidget(),"lineBr")
        self.lineBr.setFrameShape(QFrame.HLine)
        self.lineBr.setFrameShadow(QFrame.Sunken)
        self.lineBr.setFrameShape(QFrame.HLine)
        PreferencesLayout.addMultiCellWidget(self.lineBr,14,14,0,8)

        self.cancel = QPushButton(self.centralWidget(),"cancel")
        PreferencesLayout.addMultiCellWidget(self.cancel,15,15,6,7)
	self.ok = QPushButton(self.centralWidget(),"ok")
        PreferencesLayout.addWidget(self.ok,15,8)

        self.languageChange()

        self.resize(QSize(710,414).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.chooseJavaDir)
        self.connect(self.cancel,   SIGNAL("clicked()"),self.cancel_clicked)
        self.connect(self.ok,       SIGNAL("clicked()"),self.ok_clicked)
	
        self.connect(self.all,      SIGNAL("toggled(bool)"),self.showAllAction)
        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.runWeb,  SIGNAL("toggled(bool)"),self.webToggledAction)
	
        self.connect(self.deviceOver,SIGNAL("textChanged(const QString&)"),self.deviceChangedAction)

	self.receiver = mainWin
	self.cReader  = cfgReader

	self.makeGuiSetup()
	
    def makeGuiSetup(self):
	self.all.setChecked(self.cReader.showAll_)
	self.setFilters()
	
	if not self.cReader.showAll_:
	    self.appl.setChecked    (self.cReader.showApps_)
	    self.custom.setChecked  (self.cReader.showCustom_)
	    self.examples.setChecked(self.cReader.showExamples_)
	    self.at.setChecked      (self.cReader.showAt_)
	    self.srv.setChecked     (self.cReader.showSrv_)
	    self.bem.setChecked     (self.cReader.showBm_)
	
	tm = ''
	if self.cReader.updateTmout_ > 0:
	    tm = "%s" % (self.cReader.updateTmout_)
	self.tmout.setText(tm)

	tm = ''
	if self.cReader.browseTmout_ > 0:
	    tm = "%s" % (self.cReader.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(self.cReader.autoReconn_)

	self.webParams.setText(self.cReader.webParams_)
	self.deviceOver.setText(self.cReader.device_)
	self.javaDir.setText(self.cReader.javaDir_)
	
	self.setWebParamsActive(self.cReader.runWeb_)
	
	self.runWeb.setChecked(self.cReader.runWeb_ and self.cReader.device_.startswith('socket:'))
	
	self.dirView.clear()
	for d in self.cReader.cfgDirs:
	    if d != '':
        	lvi = QListViewItem(self.dirView)
        	lvi.setText(0,d)
	
	self.addDir      = ''
	self.dirsChanged = False

    def languageChange(self):
        self.setCaption(_tr("Preferences"))
        self.textLabel1.setText(_tr("Choose directories with configuration files and add them to the list"))
        self.textLabel3.setText(_tr("Show in list : "))
	self.jdirLabel.setText(_tr("Upload java 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.all.setText(_tr('All'))
        self.textLabel4.setText(_tr("Update application list every"))
        self.textLabel5.setText(_tr("sec."))
        self.textLabel7.setText(_tr("Override \"Device=\" parameter with:"))
        self.labelRunWhen.setText(_tr("Run device browser with timeout:"))
        self.runWeb.setText(_tr("Run web interface with parameters"))
        self.addButton.setText(_tr('Add'))
        self.delButton.setText(_tr('Delete'))
	self.jDir.setText(_tr('Choose'))
        self.auto_reconnect.setText(_tr("Auto reconnect in AT mode"))
        self.autoGnome.setText(_tr("Gnome session"))
        self.textLabel6.setText(_tr("Auto startup with"))
        self.autoKDE.setText(_tr("KDE session"))
        self.ok.setText(_tr('OK'))
        self.dirView.header().setLabel(0,_tr("Directories"))
        self.cancel.setText(_tr('Cancel'))

    def setWebParamsActiveReset(self):
	
	active = (self.runWeb.isChecked() and str(self.deviceOver.text()).startswith('socket:'))
	self.setWebParamsActive(active)

    def setWebParamsActive(self, active):
 
 	self.webParams.setEnabled(active)

	if active:
	    self.webParams1.setText(' -a '+self.deviceOver.text()[7:])
	else:   
            self.webParams1.setText('')

    def delete_clicked(self):
	item = self.dirView.selectedItem()
	self.dirView.takeItem(item)

	self.dirsChanged = True

    def add_clicked(self):
	f = QFileDialog().getExistingDirectory(self.addDir)
	self.addDir = os.path.dirname(str(f))
	
	add = True
	item = self.dirView.firstChild() 
        while item != None:
	    if self.addDir == item.text(0):
	        add = False
		break
	    item = item.nextSibling()
	
	if add:
       	    lvi = QListViewItem(self.dirView)
            lvi.setText(0,str(f))

    def chooseJavaDir(self):
	f = QFileDialog().getExistingDirectory(self.addDir)
	self.addDir = os.path.dirname(str(f))
	self.javaDir.setText(self.addDir)

    def deviceChangedAction(self,a0):
        self.device_ = str(self.deviceOver.text()).strip()
	self.setWebParamsActiveReset()

    def webToggledAction(self, w):
        active = self.runWeb.isChecked()
	if active:
	    isInst = isInstalled('anyremote2html')
	    if isInst == 'NOK':
		QMessageBox.warning(self, "kAnyRemote",
	                 _tr('anyremote2html is not installed !'),QMessageBox.Ok);
	    else:
		if str(self.deviceOver.text()).startswith('socket:'):
		    self.webParams1.setText(' -a '+self.deviceOver.text()[7:])
		else:
	            self.deviceOver.setText('socket:5000')
	            self.webParams1.setText(' -a 5000')
	            self.webParams.setText(' -w 5550')
		    
	self.webParams1.setEnabled(active)
	self.webParams.setEnabled(active)

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

    def ok_clicked(self):
 	self.setAutoStartup("KDE",   self.autoKDE.isChecked())
	self.setAutoStartup("Gnome", self.autoGnome.isChecked())
	
	self.cReader.showApps_     = self.appl.isChecked()
	self.cReader.showCustom_   = self.custom.isChecked()
	self.cReader.showExamples_ = self.examples.isChecked()
	self.cReader.showAll_      = self.all.isChecked()
	self.cReader.showAt_       = self.at.isChecked()
	self.cReader.showSrv_      = self.srv.isChecked()
	self.cReader.showBm_       = self.bem.isChecked()

	self.cReader.autoReconn_   = self.auto_reconnect.isChecked()
	self.cReader.runWeb_       = self.runWeb.isChecked()
	self.cReader.webParams_    = str(self.webParams.text()).strip()
	self.cReader.device_       = str(self.deviceOver.text()).strip()
	self.cReader.javaDir_      = str(self.javaDir.text()).strip()
	
	tm = str(self.tmout.text()).strip()
	if tm == '':
	    tm = '-1'
	if self.cReader.updateTmout_ != int(tm):
	    self.cReader.updateTmout_ = int(tm)
	    if self.cReader.updateTmout_ < 0:
	        self.cReader.updateTmout_ = -1
	    
	    # start/stop browser
	    sendEvent(self.receiver,20010,'')

	tm = str(self.browseTmout.text()).strip()
	if tm == '':
	    tm = '-1'
	if self.cReader.browseTmout_ != int(tm):
	    self.cReader.browseTmout_ = int(tm)
	    if self.cReader.browseTmout_ <= 0:
	        self.cReader.browseTmout_ = -1
	    
	    # start/stop updater
	    sendEvent(self.receiver,20011,'')
        
	self.cReader.cfgDirs = []
	
	item = self.dirView.firstChild() 
        while item != None:
	    self.cReader.cfgDirs.append(str(item.text(0)))
	    item = item.nextSibling()
	
	ret = QMessageBox.Ok
	if self.cReader.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:
	    self.cReader.saveConfig() 
	    self.hide()
	    
	    sendEvent(self.receiver,20005,self.dirsChanged)
	    self.dirsChanged = False

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

    def showAllAction(self, w):
    	self.dirsChanged = True
	self.setFilters()
	
    def setFilters(self):
	if self.all.isChecked():
    	    self.appl.setChecked(False)
    	    self.custom.setChecked(False)
    	    self.examples.setChecked(False)
    	    self.at.setChecked(False)
    	    self.srv.setChecked(False)
    	    self.bem.setChecked(False)
	    
    	    self.appl.setEnabled(False)
    	    self.custom.setEnabled(False)
    	    self.examples.setEnabled(False)
    	    self.at.setEnabled(False)
    	    self.srv.setEnabled(False)
    	    self.bem.setEnabled(False)
        else:
    	    self.appl.setEnabled(True)
    	    self.custom.setEnabled(True)
    	    self.examples.setEnabled(True)
    	    self.at.setEnabled(True)
    	    self.srv.setEnabled(True)
    	    self.bem.setEnabled(True)

    def setAutoStartup(self, wm, isAuto):
        if wm == 'KDE':
	    autopath = os.environ.get("HOME")+os.sep+'.kde'+os.sep+'Autostart'+os.sep+'kanyremote'
	    if isAuto:
	    	if not os.path.exists(autopath):
		    os.system('ln -s `which kanyremote` '+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+'kanyremote.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=kAnyRemote\n')
 	                f.write('Exec=kanyremote\n')
 	                f.write('Icon=kanyremote\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)

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

class QLineEditEx(QLineEdit):

    def __init__(self,parent = None, name = None, toplevel = None):
        QLineEdit.__init__(self,parent,name)
        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)

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

class kAnyRemote(QMainWindow):
    def __init__(self,cfgReader,runWizard,parent = None,name = None,fl = 0):
        QMainWindow.__init__(self,parent,name,fl)

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

	if guiMode == 'simple':
	    row = row - 1
	    
        if not name:
            self.setName("kAnyRemote")


        self.setCentralWidget(QWidget(self,"qt_central_widget"))
        kAnyRemoteLayout = QGridLayout(self.centralWidget(),1,1,11,6,"kAnyRemoteLayout")

        self.stop_button  = QPushButton(QIconSet(iconsK.loadIcon("stop",   KIcon.Small)), _tr("Stop"),          self.centralWidget())
        self.run_button   = QPushButton(QIconSet(iconsK.loadIcon("run",    KIcon.Small)), _tr("Start"),         self.centralWidget())
        self.rescan_dirs  = QPushButton(QIconSet(iconsK.loadIcon("reload", KIcon.Small)), _tr("Update Status"), self.centralWidget())
        
        kAnyRemoteLayout.addMultiCellWidget(self.stop_button,row,row,3,4)
        kAnyRemoteLayout.addMultiCellWidget(self.run_button, row,row,1,2)
        kAnyRemoteLayout.addWidget(self.rescan_dirs,row,0)

        self.listView1 = QListView(self.centralWidget(),"listView1")
        self.listView1.addColumn(_tr("Application    "))
        self.listView1.addColumn(_tr("Status     "))
        self.listView1.addColumn(_tr("Mode    "))
        self.listView1.addColumn(_tr("Type"))
        self.listView1.addColumn("F")
	
        #self.listView1.setResizeMode(QListView.AllColumns)
	self.listView1.setColumnWidthMode (0,QListView.Maximum) 
	self.listView1.setColumnWidthMode (1,QListView.Maximum) 
	self.listView1.setColumnWidthMode (2,QListView.Maximum) 
	self.listView1.setColumnWidthMode (3,QListView.Maximum) 
	self.listView1.setColumnWidthMode (4,QListView.Manual) 
	
	self.listView1.setMultiSelection(False)
	self.listView1.setSortColumn(0)
	#self.listView1.setSpacing(40)
	
	self.listView1.hideColumn(4)
	#self.listView1.setResizeEnabled(False,4) 
	
        kAnyRemoteLayout.addMultiCellWidget(self.listView1,0,0,0,4)
        
        self.details = QListView(self.centralWidget(),"details")
        self.details.addColumn('')
        self.details.header().hide()
        self.details.setMinimumHeight(self.details.header().height())
        self.details.setMaximumHeight(self.details.header().height())
        self.details.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Maximum)
	self.details.setHScrollBarMode(QScrollView.AlwaysOff)
        self.details.setRootIsDecorated(True)
        self.details.setMultiSelection(False)
        self.details.setFrameStyle(QFrame.NoFrame)
        self.details.setPaletteBackgroundColor(self.paletteBackgroundColor())
        self.connect(self.details,SIGNAL("expanded(QListViewItem*)"),self.detailExpanded)
        self.connect(self.details,SIGNAL("collapsed(QListViewItem*)"),self.detailCollapsed)
        
        kAnyRemoteLayout.addMultiCellWidget(self.details,1,1,0,4)
  
        self.detailsHead = QListViewItem(self.details)
        self.detailsHead.setText(0,_tr("Details"))       
	self.detailsHead.setOpen(False)
        self.detailsItem = QListViewItem(self.detailsHead)
        self.detailsItem.setMultiLinesEnabled(True)  
        self.detailsItem.setText(0,'')       

	if guiMode == 'expert':
            self.choose = QPushButton(QIconSet(iconsK.loadIcon("fileopen", KIcon.Small)), _tr("Choose"), self.centralWidget())
            kAnyRemoteLayout.addWidget(self.choose,2,4)
            self.cfgFile = QLineEdit(self.centralWidget(),"cfgFile")
            kAnyRemoteLayout.addMultiCellWidget(self.cfgFile,2,2,0,3)

	if debug:
            self.command = QLineEditEx(self.centralWidget(),"command",self)
            kAnyRemoteLayout.addMultiCellWidget(self.command,3,3,0,3)
            self.execcmd = QPushButton(QIconSet(iconsK.loadIcon("exec", KIcon.Small)), _tr("Execute Command"), self.centralWidget())
            kAnyRemoteLayout.addWidget(self.execcmd,3,4)
            self.execcmd.setEnabled(True)


        # File menu
        self.fileExitAction = QAction(QIconSet(iconsK.loadIcon("exit", KIcon.Small)), _tr("Exit"), QKeySequence(),self)
        self.edit_file      = QAction(QIconSet(iconsK.loadIcon("edit", KIcon.Small)), _tr("Edit"), QKeySequence(),self)
        self.start          = QAction(QIconSet(iconsK.loadIcon("run",  KIcon.Small)), _tr("Start"),QKeySequence(),self)
        self.stop           = QAction(QIconSet(iconsK.loadIcon("stop", KIcon.Small)), _tr("Stop"), QKeySequence(),self)
        self.close_window   = QAction(QIconSet(iconsK.loadIcon("fileclose", KIcon.Small)), _tr("Close Window"), QKeySequence(),self)
        
        # Edit menu
        self.save_prefs = QAction(QIconSet(iconsK.loadIcon("filesave", KIcon.Small)),  _tr("Save"),               QKeySequence(),self)
        self.properties = QAction(QIconSet(iconsK.loadIcon("configure", KIcon.Small)), _tr("Properties"),         QKeySequence(),self)
        self.chkCfg     = QAction(QIconSet(iconsK.loadIcon("button_ok", KIcon.Small)), _tr("Check Configuration"),QKeySequence(),self)
        self.dbrowser   = QAction(QIconSet(iconsK.loadIcon("filefind", KIcon.Small)),  _tr("Device Browser"),     QKeySequence(),self)
        
        # Help menu
        self.helpContentsAction = QAction(QIconSet(iconsK.loadIcon("help",  KIcon.Small)),     _tr("Help"),  QKeySequence(),self)
        self.helpAboutAction    = QAction(QIconSet(iconsK.loadIcon("about_kde", KIcon.Small)), _tr("About"), QKeySequence(),self)
        
        self.start.setOn(0)

        self.Menu = QMenuBar(self,"Menu")

        self.fileMenu = QPopupMenu(self)
        self.fileMenu.insertSeparator()
        self.fileMenu.insertSeparator()
        self.edit_file.addTo(self.fileMenu)
        self.start.addTo(self.fileMenu)
        self.stop.addTo(self.fileMenu)
        self.close_window.addTo(self.fileMenu)
        self.fileExitAction.addTo(self.fileMenu)
        self.Menu.insertItem(QString(""),self.fileMenu,1)

        self.new_menu = QPopupMenu(self)
        self.dbrowser.addTo(self.new_menu)
        self.properties.addTo(self.new_menu)
        self.chkCfg.addTo(self.new_menu)
        self.save_prefs.addTo(self.new_menu)
        self.Menu.insertItem(QString(""),self.new_menu,2)

        self.helpMenu = QPopupMenu(self)
        self.helpContentsAction.addTo(self.helpMenu)
        self.helpAboutAction.addTo(self.helpMenu)
        self.Menu.insertItem(QString(""),self.helpMenu,3)

        self.Menu.insertSeparator(4)

        self.languageChange()

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

        self.connect(self.listView1,SIGNAL('clicked(QListViewItem*, const QPoint&, int)'),self.listClicked)
	self.connect(self.listView1,SIGNAL('doubleClicked(QListViewItem*, const QPoint&, int)'), self.listDClicked)
        self.connect(self.listView1,SIGNAL('currentChanged(QListViewItem *)'), self.cursorMoved)
	
        self.connect(self.fileExitAction,SIGNAL("activated()"),self.fileExit)
        self.connect(self.edit_file,     SIGNAL("activated()"),self.edit_file_activated)
        self.connect(self.start,         SIGNAL("activated()"),self.runAction)
        self.connect(self.stop,          SIGNAL("activated()"),self.stopAction)
        self.connect(self.close_window,  SIGNAL("activated()"),self.close_window_clicked)
        
	self.connect(self.dbrowser  ,    SIGNAL("activated()"),showBrowserWin)
	self.connect(self.save_prefs,    SIGNAL("activated()"),self.saveCfg)
        self.connect(self.properties,    SIGNAL("activated()"),self.showConfDialog)
        self.connect(self.chkCfg,        SIGNAL("activated()"),showChkCfgWin)

	self.connect(self.helpContentsAction,SIGNAL("activated()"),self.helpContents)
        self.connect(self.helpAboutAction,   SIGNAL("activated()"),self.helpAbout)
	
	if guiMode == 'expert':
            self.connect(self.choose,  SIGNAL("clicked()"),self.choose_clicked)
        self.connect(self.rescan_dirs, SIGNAL("clicked()"),self.rescan_dirs_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(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()
	
	if runWizard:
	    self.showWizard()

    def languageChange(self):
    	global debug, guiMode
    
        self.setCaption("kAnyRemote")
        self.listView1.header().setLabel(0,_tr("Application"))
        self.listView1.header().setLabel(1,_tr("Status"))
        self.listView1.header().setLabel(2,_tr("Mode"))
        self.listView1.header().setLabel(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.rescan_dirs.setText(_tr("Update Status"))
        self.fileExitAction.setText(_tr("Exit"))
        self.fileExitAction.setMenuText(_tr("Exit"))
        self.fileExitAction.setAccel(QString.null)
        
	self.helpContentsAction.setText(_tr("Help"))
        self.helpContentsAction.setMenuText(_tr("Help"))
        self.helpContentsAction.setAccel(QString.null)
        
	self.helpAboutAction.setText(_tr("About"))
        self.helpAboutAction.setMenuText(_tr("About"))
        self.helpAboutAction.setAccel(QString.null)
        
	self.edit_file.setText(_tr("Edit"))
        self.edit_file.setMenuText(_tr("Edit"))
        self.edit_file.setToolTip(_tr("Edit configuration file"))
        self.start.setText(_tr("Start"))
        self.start.setMenuText(_tr("Start"))
        self.stop.setText(_tr("Stop"))
        self.stop.setMenuText(_tr("Stop"))
        self.stop.setToolTip(_tr("Stop anyRemote"))
        self.save_prefs.setText(_tr("Save"))
        self.save_prefs.setMenuText(_tr("Save"))
        self.properties.setText(_tr("Properties"))
        self.properties.setMenuText(_tr("Properties"))
        self.chkCfg.setText(_tr("Check configuration"))
        self.chkCfg.setMenuText(_tr("Check configuration"))
        self.dbrowser.setText(_tr("Device Browser"))
        self.dbrowser.setMenuText(_tr("Device Browser"))
        if self.Menu.findItem(1):
            self.Menu.findItem(1).setText(_tr("File"))
        if self.Menu.findItem(2):
            self.Menu.findItem(2).setText(_tr("Setup"))
        if self.Menu.findItem(3):
            self.Menu.findItem(3).setText(_tr("Help"))
  
    def showWizard(self):
   	ret = QMessageBox.information(self, "kAnyRemote",
	             _tr("This is the first time kAnyRemote runs.\nPlease specify directories with anyRemote configuration files."),QMessageBox.Ok);
	self.showConfDialog()

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

    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 = QListViewItem(self.listView1)
       lvi.setPixmap(0,rowData[1])
       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, point, column):
        global debug, lastCfgFile, appData, guiMode
	try:
	    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(lastCfgFile)
	except AttributeError:
	    if debug: print 'kAnyRemote.listClicked: AttributeError'
	

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

    def cursorMoved(self):
        global debug, lastCfgFile, appData, guiMode
	try:
	    listItem = self.listView1.currentItem()
	    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(lastCfgFile)
	except AttributeError:
	    if debug: print 'kAnyRemote.cursorMoved: AttributeError'
	
    def fileExit(self):
    	global app, quitFlag, debug
	
        if debug: print "kAnyRemote.fileExit"
	quitFlag = True
	
	closeDetailsWin()
	closeBrowserWin()
	closeChkCfgWin()
	
	self.stopUpdater()
	stopFrontend()
	stopBtComm()
	
	time.sleep(0.5)
	
	if debug: print "kAnyRemote.fileExit -> app.quit"
	app.quit()

    def helpContents(self):
 	# open web browser on docs page if found ?
	app = 'firefox'
	isInst = isInstalled(app)
	if isInst == 'NOK':
	    app = 'konqueror'
	    isInst = isInstalled(app)
	    
	    if isInst == 'NOK':
	        errorMessage(self, 'Did not find browser to show help !')
		return
		
	docpath = ''
	if os.path.isdir('/usr/share/doc/anyremote/doc-html'):
	    docpath = '/usr/share/doc/anyremote/doc-html'
	elif os.path.isdir('/usr/local/share/doc/anyremote/doc-html'):
	    docpath = '/usr/local/share/doc/anyremote/doc-html'
	elif os.path.isdir('/usr/share/anyremote/doc-html'):
	    docpath = '/usr/share/anyremote/doc-html'
	elif os.path.isdir('/usr/local/share/anyremote/doc-html'):
	    docpath = '/usr/local/share/anyremote/doc-html'
	else:    
	    errorMessage('Can not find documentation !')
	    return
	
	cmd = app + ' ' + docpath + os.sep + 'k-shots.html &'
	os.system(cmd)

    def helpAbout(self):
 	global aboutData
	a = KAboutApplication(aboutData,self,"kAnyRemote",0)
	a.show()

    def edit_file_activated(self):
        global lastCfgFile
        if lastCfgFile:
	    self.eWin = EditWin(lastCfgFile)
	    self.eWin.show()

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

    def rescan_dirs_clicked(self):
	self.populateCfgFiles()
    
    def closeEvent(self, event):
        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.cReader.saveConfig()
	
	# To avoid socket.error: (98, 'Address already in use') 
	# it needs to close client socket first
        killAnyRemote()

	self.setStatusStopped()

    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, lastCfgFile

        if debug: print "kAnyRemote.runAction()"
        
	self.cReader.saveConfig()
	
	self.setStatusDisconnected()
        
        cfile = lastCfgFile
        if guiMode == 'expert':
 	     cfile = self.cfgFile.text()

	startAnyRemote(cfile, self.cReader.runWeb_)	
			    
    def restartUpdater(self):
        self.stopUpdater()
	self.startUpdater()

    def startUpdater(self):
        if self.cReader.updateTmout_ > 0:
    	    self.statusUpdater = StatusUpdater(self,self.cReader.updateTmout_)
    	    self.statusUpdater.start()

    def stopUpdater(self):
	try:
	    self.statusUpdater.stop()
	except AttributeError, NameError:
	    pass

	time.sleep(0.5)

    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'
	    
	self.stopUpdater()

	cfgFileReader = CfgFileReader(self, self.cReader)
	cfgFileReader.start()
	
    def setStatustext(self,text):
        self.statusBar().clear()
        self.statusBar().message(text)
	
    def setStatusStopped(self):
        setIcon("kanyremote_off")
	self.conn_status = 0
	
	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):
        setIcon("kanyremote_light")
	self.conn_status = 1
	self.setStatustext(_tr('Disconnected from phone'))
	
        self.stop.setEnabled(True)
	self.start.setEnabled(False)
	self.stop_button.setEnabled(True)
	self.run_button.setEnabled(False)

    def setStatusConnected(self):
        setIcon("kanyremote")
	self.conn_status = 2
	self.setStatustext(_tr('Connected to phone'))
	
    def listUpdate(self, data):
        #print 'listUpdate',data
	st = self.getStatus(data[2],data[1])

	item = self.listView1.firstChild() 
        while item != None:
	    try:
	        if int(item.text(4)) == data[0]:
	            item.setText(1,st)
	            break
            except ValueError:
	        pass   
	    item = item.nextSibling()

    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.isOpen():
            self.details.setMinimumHeight(self.details.header().height()*(cnt+2))
            self.details.setMaximumHeight(self.details.header().height()*(cnt+2))

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

	item = self.listView1.firstChild() 
        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   
	    item = item.nextSibling()
    
    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   
    	   self.bTh = BlinkThread(self)
    	   self.bTh.start()
	   if debug:
	       msg = data
	   else:
	       return
	
	self.setStatustext(msg)

	    
    def customEvent(self,event):
        global appData
	
	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];}\'', '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:
           setIcon("kanyremote_flash")
        elif event.type() == 20002:
           setIcon("kanyremote")
        elif event.type() == 20005:
           self.cfgWinClosed(event.data())
        elif event.type() == 20006:
           self.listUpdate(event.data())
        elif event.type() == 20007:
	   self.listView1.clear()
	   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])
	   self.selectLastInList()
           self.restartUpdater()
        elif event.type() == 20008:
           self.dcopHandleSend(event.data())
        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])
        else:
           self.translateMsg(event.data())
           
    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')
        self.details.setMinimumHeight(self.details.header().height()*(cnt+2))
        self.details.setMaximumHeight(self.details.header().height()*(cnt+2))

    def detailCollapsed(self, item):
        self.details.setMinimumHeight(self.details.header().height())
        self.details.setMaximumHeight(self.details.header().height())
        	
    
###############################################################################	
#
#	Configuration management
#
###############################################################################	

class ConfigReader:
    def saveConfig(self):
    
    	global lastCfgFile
	
    	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='+lastCfgFile+'\n')
	    
	    if self.showAll_:
	        f.write('Show=All\n')
	    else:
	    	what = 'Show='
		if self.showApps_:
		    what = what + 'Apps,'
		if self.showCustom_:
		    what = what + 'Custom,'
		if self.showExamples_:
		    what = what + 'Examples,'
		if self.showAt_:
		    what = what + 'AT,'
		if self.showSrv_:
		    what = what + 'Server,'
		if self.showBm_:
		    what = what + 'Bemused,'
	    	
		f.write(what+'\n')

	    ac = '0'
            if self.autoReconn_:
	        ac = '1'
 	    f.write('AutoReconnectAT='+ac+'\n')
	    
	    if self.runWeb_:
	        f.write('WebInterface='+self.webParams_+'\n')

	    if self.device_ != '':
	        f.write('OverrideDevice='+self.device_+'\n')

	    #if self.updateTmout_ != -1:
	    tm = "%s" % (self.updateTmout_)
	    f.write('UpdateTimeout='+tm+'\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('JavaDir='+self.javaDir_+'\n')
	    
	    f.close()
	    
	# device browser related part
	f=open(cfg + os.sep + 'anyremote-peers.conf', 'w')
	if f:
	    for k, v in bt_devices.iteritems():

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

	    f.close()

    def setDefaultConfig(self):
    	global lastCfgFile

	lastCfgFile        = ''
	self.cfgDirs       = []	
	self.javaDir_      = ''	
	self.showApps_     = True
	self.showCustom_   = False
	self.showExamples_ = False
	self.showAt_       = False
	self.showSrv_      = True
	self.showBm_       = False
	self.showAll_      = False
	self.autoReconn_   = False
	self.device_       = ''
	self.runWeb_       = False
	self.webParams_    = ''
	self.updateTmout_  = 60
	self.browseTmout_  = -1
	
    def readConfig(self):
    	global lastCfgFile, bt_devices
	
       	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','')
		    os.path.exists(cfg) 
		    if line.startswith('LastCfgFile='):
		        lastCfgFile=line[12:]
		    elif line.startswith('Show='):
		    	#Show=Apps,Custom,Examples|All
			what = line[5:].split(',')
			
			# override defaults
	                self.showApps_ = False
			self.showSrv_  = False
			
			for item in what:
			   if item == 'All':
			      self.showAll_ = True
			   elif item == 'Apps':
			      self.showApps_ = True
			   elif item == _tr('Custom'):
			      self.showCustom_ = True
			   elif item == 'Examples':
			      self.showExamples_ = True
			   elif item == 'AT':
			      self.showAt_ = True
			   elif item == 'Server':
			      self.showSrv_ = True
			   elif item == 'Bemused':
			      self.showBm_ = True
			      
		    elif line.startswith('AutoReconnectAT='):
		        self.autoReconn_ = (line == 'AutoReconnectAT=1')
		    elif line.startswith('OverrideDevice='):
		        self.device_ = line[15:]
		    elif line.startswith('WebInterface='):
		        self.runWeb_    = True
		        self.webParams_ = line[13:]
                    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('JavaDir='):
		        self.javaDir_=line[8:]
		    
	    	f.close()
	        
		# Try to search again
		if self.javaDir_ == '':
		    self.javaDir_ = getJ2MEPath()

		
	# device browser related part
       	cfg  = os.environ.get("HOME")+os.sep+'.anyRemote' + os.sep + 'anyremote-peers.conf'
	
    	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(',')
			
			v1 = deviceData[0]
			v2 = deviceData[1]
			v3 = deviceData[2]
			v4 = deviceData[3]
			
			bt_devices[v1] = [v1,v2,v3,v4,'']
	    	f.close()
	
##################################################################################
#
# Utilities functions
#
##################################################################################

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('pkill -f "python .*anyremote2html"')
    os.system('killall -2 anyremote 2> /dev/null')
    
def startAnyRemote(cfile, webIface):
    global debug, cfgReader, port
    
    killAnyRemote()
	
    time.sleep(0.5)

    web = ''
    if webIface:
    	web = ' -http'

    dev = ''
    if cfgReader.device_ != '':
    	dev = ' -s '+ cfgReader.device_

    log = ''
    if debug:
    	log = ' -log'

    useType = getMode(cfile)
    
    rconn = ''
    if cfgReader.autoReconn_ != '' and (useType == 'AT' or useType == ''):
    	    rcomm = ' -a '
    	    
    to_path = os.environ.get("HOME") + os.sep + '.anyRemote' + os.sep

    cmd = 'anyremote -fe ' + port + log + web + ' -f ' + str(cfile) + dev + rconn + ' > '+ to_path + 'anyremote.stdout &'
    if debug: print cmd
    os.system(cmd)
    
    if webIface:
        dd = ''
    	if debug: dd = '-d '
  
        cmd = 'anyremote2html ' + dd + ' -a ' + cfgReader.device_[7:] + ' ' + cfgReader.webParams_ + ' > '+ to_path + 'anyremote2html.stdout &'
        if debug: print cmd
        os.system(cmd)

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

def sendEvent(receiver, eid, data):
    global quitFlag, app
    
    if quitFlag: return
    
    event = QCustomEvent(eid)
    event.setData(data)
    app.postEvent(receiver, event)

def setIcon(iconName):
    global systray, iconsK
    if systray:
        systray.setPixmap (iconsK.loadIcon(iconName, KIcon.Small))

def errorMessage(widget, message):
    ret = QMessageBox.warning(widget,"kAnyRemote",message,QMessageBox.Ok);

def infoMessage(widget, message):
    ret = QMessageBox.warning(widget,"kAnyRemote",message,QMessageBox.Ok);

def getJ2MEPath():
    path = ''
    if os.path.exists('/usr/share/anyremote-J2ME-client'):
        path = '/usr/share/anyremote-J2ME-client'
    elif os.path.exists('/usr/local/share/anyremote-J2ME-client'):
        path = '/usr/local/share/anyremote-J2ME-client'
    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 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 btVerify(window,showmsg):
    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 showmsg and hcid == 'NOK':
        infoMessage(window,'Bluetooth service is not active')
    return hcid

def initVerify(window):

    tool = isInstalled('anyremote')
    if tool == 'NOK':
        errorMessage(window, _tr('anyRemote not found !\nPlease install it or correct $PATH'))

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

    z = btVerify(window,True)

def showDetailsWin(v1,v2,v3,v4,v5):
    global dwin, cfgReader
    dwin = DeviceDetail(v1, v2, v3, v4, v5, cfgReader.javaDir_)
    dwin.show()
    
def closeDetailsWin():
    global dwin
    try:
        dwin.destroy()
        dwin = 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[4] == AR_AVAIL:
	    s.append(v[0])
    
    return Set(s)

def getDevSet():
    global bt_devices

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

    return True

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

    if cfgReader.browseTmout_ > 0 and not quitFlag:
    	browseDevices()
    	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.javaDir_)
    	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(receiver):
    if debug: print 'startFrontend',cmd_array
    global frontEnd
    frontEnd = FrontEnd(receiver)
    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
	
    frontEnd = None

##################################################################################
#
# DCOP
#
##################################################################################

class kAnyRemote_DCOP (DCOPExObj):
    def __init__ (self, rcv, id="anyRemote"):
        DCOPExObj.__init__ (self, id)
        self.receiver = rcv

        self.addMethod ("void sendCommand(QString)", self.sendCommand)
        self.addMethod ("bool isConnected()", self.isConnected)

    def sendCommand(self, cmd):
        sendEvent(self.receiver,20008,cmd)

    def isConnected(self):
        return (self.receiver.conn_status == 2)

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

def main():

    global app, aboutData, systray, iconsK, debug, port, statusUpdater, cmdToSend, guiMode, usepybluez, usetray, cfgReader
	
    cmdToSend     = ''
    statusUpdater = ''
    guiMode       = 'simple'
    usepybluez    = True
    usetray       = True
    
    description = 'KDE front-end for anyRemote (bluetooth remote control for PC)'
    version     = "5.3"

    aboutData = KAboutData ("kanyremote", "kanyremote", version, description, KAboutData.License_GPL, "(C) 2007, 2008 Mikhail Fedotov")
    aboutData.addAuthor ("Mikhail Fedotov", "", "anyremote@mail.ru")

    sys.argv.extend(['--icon', 'kanyremote', '--caption', "kAnyRemote"])
		     
    KCmdLineArgs.init (sys.argv, aboutData)
    KCmdLineArgs.addCmdLineOptions ([("d", "Debug"),("debug", "Debug"),
                                     ("n", "Do not use PyBluez"),
                                     ("npybluez", "Do not use PyBluez"),
                                     ("t", "Do not use tray icon"),
                                     ("ntray", "Do not use tray icon"),
                                     ("e", "Expert mode"),
				     ("expert", "Expert mode"),
                                     ("p ", "Port"),
				     ("port ", "Port"),
				     ("o", "Open window")])
    
    app = KApplication()
    
    args = KCmdLineArgs.parsedArgs();
    
    if args.isSet("d") | args.isSet("debug"):
	debug   = True
        guiMode = 'expert'
    
    if args.isSet("e") | args.isSet("expert"):
        guiMode = 'expert'
   
    if args.isSet("p"):
	q = args.getOption('p')
	port = str(q.data()).replace('\0','')

    if args.isSet('port'):
	q = args.getOption('port')
	port = str(q.data()).replace('\0','')

    if args.isSet('ntray') | args.isSet('t'):
        usetray = False
	
    if args.isSet("n") | args.isSet("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)

    needWiz = False
    cfgReader = ConfigReader()
    cfgReader.setDefaultConfig()
    if os.path.exists(cfg+os.sep+'anyremote-fe.conf'):
	cfgReader.readConfig()
    else: 
        cfgSet = False
    
	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/')
	    
	cfgReader.javaDir_ = getJ2MEPath()
	
        if not cfgSet or cfgReader.javaDir_ == '':
            needWiz = True
    
    iconsK = KIconLoader()
	
    mainWindow = kAnyRemote(cfgReader, needWiz, None, "kAnyRemote")
    
    dcop = kAnyRemote_DCOP(mainWindow,'anyRemote')
    
    if args.isSet("o") or not usetray:
        mainWindow.isShown = 1
        mainWindow.show()
    else:
        mainWindow.isShown = 0
    
    initVerify(mainWindow)

    systray = None
    if usetray:
        systray = KSystemTray (mainWindow)
        setIcon("kanyremote_off")
    
        pmenu = systray.contextMenu()

        pmenu.insertItem(QIconSet(iconsK.loadIcon("run",  KIcon.Small)), "Start", mainWindow.runAction,  QKeySequence(),3,3)
        pmenu.insertItem(QIconSet(iconsK.loadIcon("stop", KIcon.Small)), "Stop",  mainWindow.stopAction, QKeySequence(),4,4)

        app.connect(systray, SIGNAL("quitSelected()"), mainWindow.fileExit)
        systray.show ()

    app.connect(app, SIGNAL("lastWindowClosed()"), app, SLOT("quit()"))
	    
    mainWindow.setStatusStopped()
   
    startFrontend(mainWindow)
    
    app.exec_loop()

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

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