#!/usr/bin/python
# -*- coding: utf-8 -*-
# Translation in English by David Dumas
"""
Allow the user to manage Access Points in an independent module.
This file is specifically dedicated to IHM_AP.py, UI file for the module of Access Points management.
"""
import pg
import re
import sys
import time
import string
import logging
import ConfigParser
import threading
from PyQt4 import QtGui, QtCore
from ihm_AP import *
from code.DBA import *
from code.popups import *
from PyQt4.QtGui import *
from WifiScanner import *
[docs]class APController(QtGui.QWizard):
"""
Create the wizard. Assign functions to the various buttons.
"""
def __init__(self, main=None, parent=None):
"""
Called every time this class is instantiated. It’s the equivalent of a class constructor in C/C++.
It initializes the UI of the measurement part in four steps:
- Creation of the link with the main UI
- Creation of the UI
- Creation of the event listeners generated by the UI via “connect_signals()”
- Variables initializations via “initVariables()”
"""
QtGui.QWidget.__init__(self, parent=parent)
# Keeps link towards high_level application
self.main_app = main
# Draws UI
self.ui = Ui_AP()
self.ui.setupUi(self)
# Connects signals of UI to self methods
self.connect_signals()
# Initialization
self.initVariables()
# Load APs
self.loadAP()
[docs] def initVariables(self):
"""
Initialize the variables necessary to do measures and connect to the database.
"""
# Init various variables to false
self.ui.toolButton_ap_ajouter.setEnabled(False)
self.ui.toolButton_ap_supprimer.setEnabled(False)
self.ui.toolButton_ap_modifier.setEnabled(False)
# Connect to the database with the parameters from the conf file
self.db = DBConnect(main=self.main_app)
self.ids_environments = {} # Dictionary to store the environement in the UI { key => string displayed : value => environnement ID (in the database) }
self.id_environment = None # Environnement ID selected by the user (Window 1)
self.ids_places = {} # Dictionary to store the locations displayed in the UI { key => string displayed : value => location ID (in the database) }
self.id_place = None # Location ID selected by the user (Window 2)
self.ids_aps = {} # Dictionary of the APs { key => string displayed : value => AP ID (in the database) }
self.id_ap = None # AP ID selected by the user
# Instanciation of class Popup
self.popup=Popups()
# Instanciation of class WifiScanner
self.scanner=WifiScanner()
#init treeWidget
self.ui.treeWidget.header().setStretchLastSection(False)
self.ui.treeWidget.header().setResizeMode(0, QHeaderView.Stretch)
#self.ui.treeWidget.header().setResizeMode(1, QHeaderView.Stretch)
self.ui.treeWidget.header().setResizeMode(2, QHeaderView.Stretch)
self.listItemsAP=[]
[docs] def connect_signals(self):
"""
Create action listeners for the UI.
Example: self.connect(self.ui.toolButton_mesure_campagne_ajouter, QtCore.SIGNAL("clicked()"), self.ajouterCampagne)
When the bouton “toolButton_mesure_campagne_ajouter” is clicked, function “ajouterCampagne()” is called.
"""
# Buttons links with functions
self.connect(self, QtCore.SIGNAL("currentIdChanged(int)"), self.switchPage)
self.connect(self, QtCore.SIGNAL("rejected()"), self.main_app.switchToMenu)
self.connect(self, QtCore.SIGNAL("finished(int)"), self.reinitialize)
self.connect(self.ui.listWidget_ap_environnement, QtCore.SIGNAL("itemClicked(QListWidgetItem *)"), self.setCurrentEnvironment)
self.connect(self.ui.listWidget_ap_lieu, QtCore.SIGNAL("itemClicked(QListWidgetItem *)"), self.setCurrentLocation)
self.connect(self.ui.listWidget_ap_list, QtCore.SIGNAL("itemClicked(QListWidgetItem *)"), self.displayAPInfo)
self.connect(self.ui.toolButton_ap_ajouter, QtCore.SIGNAL("clicked()"), self.addAP)
self.connect(self.ui.toolButton_ap_supprimer, QtCore.SIGNAL("clicked()"), self.removeAP)
self.connect(self.ui.toolButton_ap_modifier, QtCore.SIGNAL("clicked()"), self.editAP)
# Grey out the add AP button when the fields are not filled
self.connect(self.ui.lineEdit_ap_essid, QtCore.SIGNAL("textChanged (const QString&)"), self.enableAddAP)
self.connect(self.ui.lineEdit_ap_MAC, QtCore.SIGNAL("textChanged (const QString&)"), self.enableAddAP)
self.connect(self.ui.lineEdit_ap_coor_x, QtCore.SIGNAL("textChanged (const QString&)"), self.enableAddAP)
self.connect(self.ui.lineEdit_ap_coor_y, QtCore.SIGNAL("textChanged (const QString&)"), self.enableAddAP)
self.connect(self.ui.lineEdit_ap_coor_z, QtCore.SIGNAL("textChanged (const QString&)"), self.enableAddAP)
# Grey out the delete AP button when no AP is selected
self.connect(self.ui.listWidget_ap_list, QtCore.SIGNAL("itemClicked(QListWidgetItem *)"), self.enableRemoveAP)
# Grey out the update AP button when no AP is selected
self.connect(self.ui.listWidget_ap_list, QtCore.SIGNAL("itemClicked(QListWidgetItem *)"), self.enableEditAP)
#listAP
self.connect(self.ui.treeWidget, QtCore.SIGNAL("itemSelectionChanged()"), self.selectAP)
self.connect(self.ui.refresh, QtCore.SIGNAL("clicked()"),self.loadAP)
[docs] def switchPage(self):
"""
Called whenever a UI page change occurs to initialize:
- Lists fulfillment (pages 1 to 4)
- Measurements (page 5)
- Completion of the measures (page 6)
"""
if self.currentId() == 1:
logging.info('Page : Environment (AP)')
self.displayEnvironmentList()
if self.currentId() == 2:
logging.info('Page : Place (AP)')
self.displayLocationList()
if self.currentId() == 3:
logging.info('Page : Add AP (AP)')
self.displayAPList()
self.clearAPInfo()
[docs] def reinitialize(self, resultCode):
"""
Switch to the application master menu and reinitializes the QWizard module.
"""
self.main_app.switchToMenu()
self.restart()
[docs] def validateCurrentPage(self):
"""
Reimplementation of the function “validateCurrentPage” which implements by default “QWizardPage::validatePage()” on “currentPage()”.
@return: [ True: page validated + ID changed ==> panel switch / False: page non-compliant + same ID ==> no panel switch ]
"""
# Check if any environnement is selected
if self.currentId() == 1:
if not self.ui.listWidget_ap_environnement.currentItem():
return False
# Check if any location is selected
if self.currentId() == 2:
if not self.ui.listWidget_ap_lieu.currentItem():
return False
return True
#----------Environnement selection page-----
[docs] def displayEnvironmentList(self):
"""
Display the list of environments in the UI.
"""
# Empty the list in the UI
self.ui.listWidget_ap_environnement.clear()
# Select the name, coordinates X,Y,Z and the description of locations in the database
result_sql=self.db.select('area',['id_area','name', 'description'])
# Update the list in the UI with the info retrieved just before
for id_area, name, description in result_sql:
str = "%s : %s" % (name, description)
self.ids_environments[str] = id_area
self.ui.listWidget_ap_environnement.addItem(str)
[docs] def setCurrentEnvironment(self):
"""
Retrieve the name and database ID of the selected environment.
"""
# Retrieve the ligne selected in the UI
line_select = str(self.ui.listWidget_ap_environnement.currentItem().text())
# Retrieve the ID
self.id_environment = self.ids_environments[line_select]
#----------Location selection page--------------
[docs] def displayLocationList(self):
"""
Display the list of locations in the UI.
"""
# Empty the list in the UI
self.ui.listWidget_ap_lieu.clear()
# Select the name, coordinates X,Y,Z and the description of locations in the database
result_sql=self.db.select('place',['id_place', 'name','description'],{'id_area':self.id_environment})
# Update the list in the UI with the info retrieved just before
for id_place, name, description in result_sql:
str = "%s : %s" % (name, description)
self.ids_places[str] = id_place
self.ui.listWidget_ap_lieu.addItem(str)
[docs] def setCurrentLocation(self):
"""
Retrieve the name and database ID of the selected location. Set a global variable “self.id_place”.
"""
# Retrieve the ligne selected in the UI
line_select = str(self.ui.listWidget_ap_lieu.currentItem().text())
# Retrieve the ID
self.id_place = self.ids_places[line_select]
#----------Add and edit APs page--------------
[docs] def displayAPList(self):
"""
Display the list of Access Points in the UI.
"""
# Empty the list in the UI
self.ui.listWidget_ap_list.clear()
# Select the name, coordinates X,Y,Z and the description of locations in the database
result_sql = self.db.select('ap',['id_ap','essid','mac_address','x_coordinate_place',\
'y_coordinate_place','z_coordinate_place','description'],{'id_place':self.id_place,'essid !':'\'AP_ignored\''})
# Update the list in the UI with the info retrieved just before
for id_ap, essid, mac_address, x_coordinate_place, y_coordinate_place, z_coordinate_place, description in result_sql:
str = "%s %s - %s" % (essid, mac_address, description)
self.ids_aps[str] = id_ap
self.ui.listWidget_ap_list.addItem(str)
self.ui.listWidget_ap_list.sortItems()
# Grey out the AP delete and update buttons
self.ui.toolButton_ap_supprimer.setEnabled(False)
self.ui.toolButton_ap_modifier.setEnabled(False)
[docs] def setCurrentAP(self):
"""
Retrieves the ID depending on the Access Point selected in the UI.
"""
# Retrieve the ligne selected in the UI
line_select=str(self.ui.listWidget_ap_list.currentItem().text())
# Retrieve the ID
self.id_ap = self.ids_aps[line_select]
[docs] def clearAPInfo(self):
"""
Clear the user filled fields. Called whenever the Access Points list is updated.
"""
# Empty all the fields
self.ui.lineEdit_ap_essid.clear()
self.ui.lineEdit_ap_MAC.clear()
self.ui.textEdit_ap_description.clear()
self.ui.lineEdit_ap_coor_x.clear()
self.ui.lineEdit_ap_coor_y.clear()
self.ui.lineEdit_ap_coor_z.clear()
[docs] def displayAPInfo(self):
"""
Display the Access Point’s parameters when an element is selected in the list.
"""
# Retrieve the ID of the selected AP
self.setCurrentAP()
# Retrieve the info of the ligne selected
result_sql = self.db.select('ap',['essid','mac_address','x_coordinate_place',\
'y_coordinate_place','z_coordinate_place','description'],{'id_ap':self.id_ap})
# Display the parameters in the add / modify fields of the UI
for essid, mac_address, x_coordinate_place, y_coordinate_place, z_coordinate_place, description in result_sql:
self.ui.lineEdit_ap_essid.setText(QtCore.QLatin1String(str(essid)))
self.ui.lineEdit_ap_MAC.setText(QtCore.QLatin1String(str(mac_address)))
self.ui.lineEdit_ap_coor_x.setText(QtCore.QLatin1String(str(x_coordinate_place)))
self.ui.lineEdit_ap_coor_y.setText(QtCore.QLatin1String(str(y_coordinate_place)))
self.ui.lineEdit_ap_coor_z.setText(QtCore.QLatin1String(str(z_coordinate_place)))
self.ui.textEdit_ap_description.setText(QtCore.QLatin1String(str(description)))
[docs] def verifyAPInfo(self, mac, ap_x, ap_y, ap_z, essid, appel):
"""
Integrity check of the user’s input before insertion in the database.
Verify the MAC address’ format, the coordinates’ consistency in a location and duplicates of an entry with the same SSID and MAC address.
@param appel: by which function this function is call [ True: from addAP() / False: from editAP()]
"""
# Check the MAC address format
match = re.match("[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}$", mac)
if not match:
self.displayAPList()
self.popup.popupOK("MAC adress format error ", "The MAC adress synthaxe is :\n 00:00:00:00:00:00" )
return False
# Check the X coordinate
x_coor_place = self.db.select('place',['length'], {'id_place':self.id_place})[0][0]
if int(ap_x) > x_coor_place:
if not self.popup.popupYesNo("Out of local area","Warning, your AP is out of the place (X>%dm). Do you really want to continue ?" % x_coor_place):
self.displayAPList()
return False
# Check the Y coordinate
y_coor_place = self.db.select('place',['width'], {'id_place':self.id_place})[0][0]
if int(ap_y) > y_coor_place:
if not self.popup.popupYesNo("Out of local area","Warning, your AP is out of the place (Y>%dm). Do you really want to continue ?" % y_coor_place):
self.displayAPList()
return False
# Check the Z coordinate
z_coor_place = self.db.select('place',['height'], {'id_place':self.id_place})[0][0]
if int(ap_z) > z_coor_place:
if not self.popup.popupYesNo("Out of local area","Warning, your AP is out of the place (Z>%dm). Do you really want to continue ?" % z_coor_place):
self.displayAPList()
return False
# Check if the MAC-ESSID pair exists already in the database
if appel:
# Add function
if not self.db.select('ap',['id_ap'],{'essid':'\'' + essid + '\'','mac_address':'\'' + mac + '\''})== []:
self.displayAPList()
self.popup.popupOK("This pair of \"MAC - SSID\" already exist !", "It's not possible to create the AP !\nAn AP already exists in the DB with the SSID \"" + essid + "\" and the MAC adress \"" + mac + "\".")
return False
else:
# Edit function : check if any AP in the database has already the specified SSID-MAC pair, except the currently selected pair
if not self.db.select('ap',['id_ap'],{'essid':'\'' + essid + '\'','mac_address':'\'' + mac + '\'','id_ap !':self.id_ap})== []:
self.displayAPList()
self.popup.popupOK("This pair of \"MAC - SSID\" already exist !", "It's not possible to create the AP \"id " + str(self.id_ap) + "\" !\nAn other AP already exist in the DB with the SSID \"" + essid + "\" and the MAC adress \"" + mac + "\".")
return False
# Conditions satisfied ==> return True
return True
[docs] def addAP(self):
"""
Add an Access Point into the database.
"""
# Retrieve the info filled in the UI
essid = str(self.ui.lineEdit_ap_essid.text())
mac = str(self.ui.lineEdit_ap_MAC.text())
desc_ap = str(self.ui.textEdit_ap_description.toPlainText()).replace("'", "\\'")
ap_x = str(self.ui.lineEdit_ap_coor_x.text())
ap_y = str(self.ui.lineEdit_ap_coor_y.text())
ap_z = str(self.ui.lineEdit_ap_coor_z.text())
# Retrieve the location the user is working with
self.setCurrentLocation()
# Create a dictionary allowing to define parameters that will be loaded in the database
dic = {'essid':essid, 'mac_address':mac, 'x_coordinate_place':ap_x,'y_coordinate_place':ap_y,\
'z_coordinate_place':ap_z,'description':desc_ap,'id_place':self.id_place}
# Insert in the database if the conditions are satisfied
if self.verifyAPInfo(mac, ap_x, ap_y, ap_z, essid, True):
try:
# Insert in the database with the DBA module and the function 'insert', retrieve the added AP's ID.
self.id_ap = self.db.insertAndReturn("ap", dic, 'id_ap')
# If it suceeds, empty the fields
self.clearAPInfo()
except pg.DatabaseError, exc:
# If there is a value for any coordinate (x,y or z), perform an 'update' instead of an 'insert'
print "There ever is this AP in the BDD, use the edit button to modify \n"
from traceback import format_exc
print format_exc()
# Update the list
self.displayAPList()
[docs] def removeAP(self):
"""
Remove an Access Point from the database.
"""
# Display the AP list
self.displayAPList()
# Pop up a confirmation dialog to delete the AP
validate_remove = self.popup.popupYesNo("AP remove confirmation", "Do you really want to remove the selected AP ?")
# Delete the AP from the database after confirmation
if validate_remove:
self.db.delete("ap", {'id_ap':self.id_ap})
# Update the AP list in the UI
self.displayAPList()
# Clear the fields
self.clearAPInfo()
[docs] def editAP(self):
"""
Edit an Access Point’s parameters in the database.
"""
# Retrieve the info filled in the UI
essid = str(self.ui.lineEdit_ap_essid.text())
mac = str(self.ui.lineEdit_ap_MAC.text())
desc_ap = str(self.ui.textEdit_ap_description.toPlainText()).replace("'", "\\'")
ap_x = str(self.ui.lineEdit_ap_coor_x.text())
ap_y = str(self.ui.lineEdit_ap_coor_y.text())
ap_z = str(self.ui.lineEdit_ap_coor_z.text())
# Integrity check on the modified fields
if self.verifyAPInfo(mac, ap_x, ap_y, ap_z, essid, False):
# Update the parameters of the AP in the database
self.db.update("ap", "essid", '\''+essid+'\'', {'id_ap':self.id_ap})
self.db.update("ap", "mac_address", '\''+mac+'\'', {'id_ap':self.id_ap})
self.db.update("ap", "x_coordinate_place", ap_x, {'id_ap':self.id_ap})
self.db.update("ap", "y_coordinate_place", ap_y, {'id_ap':self.id_ap})
self.db.update("ap", "z_coordinate_place", ap_z, {'id_ap':self.id_ap})
self.db.update("ap", "description", '\''+desc_ap+'\'', {'id_ap':self.id_ap})
# Clear the fields if the edit succeeds
self.clearAPInfo()
# Update the AP list in the UI
self.displayAPList()
[docs] def enableAddAP(self):
"""
Activates / deactivates the button to add Access Points. The button becomes active only when the user fills the required fields (SSID, MAC address, coordinates).
"""
# Check if the fields exist, if yes: activate the "Ajouter" button / if no: the "Ajouter" button remains greyed out
if self.ui.lineEdit_ap_essid.text() and self.ui.lineEdit_ap_MAC.text() \
and self.ui.lineEdit_ap_coor_x.text() and self.ui.lineEdit_ap_coor_y.text() and self.ui.lineEdit_ap_coor_z.text():
self.ui.toolButton_ap_ajouter.setEnabled(True)
else :
self.ui.toolButton_ap_ajouter.setEnabled(False)
[docs] def enableRemoveAP(self, itemClicked):
"""
Activates / deactivates the button “toolButton_ap_supprimer” whenever an Access Point is selected in the list.
"""
if itemClicked:
self.ui.toolButton_ap_supprimer.setEnabled(True)
else :
self.ui.toolButton_ap_supprimer.setEnabled(False)
[docs] def enableEditAP(self, itemClicked):
"""
Activates / deactivates the button “toolButton_ap_modifier” whenever an Access Point is selected in the list.
"""
if itemClicked:
self.ui.toolButton_ap_modifier.setEnabled(True)
else :
self.ui.toolButton_ap_modifier.setEnabled(False)
[docs] def selectAP(self):
"""
Select an AP from the scanned list
"""
print "AP select"
elements= self.ui.treeWidget.selectedItems()
#self.setWindowTitle ( test[0].text(0) + "\t" + test[0].text(2) )
self.SSID = elements[0].text(0)
self.mac = elements[0].text(2)
self.completionAP(self.SSID,self.mac)
[docs] def completionAP(self,ssid,mac):
"""
auto completion
"""
print ssid + ' ' + mac
self.ui.lineEdit_ap_essid.setText(ssid)
self.ui.lineEdit_ap_MAC.setText(mac)
[docs] def loadAP(self):
"""
load the AP
"""
self.ui.treeWidget.clear()
self.listItemsAP=[]
self.ui.refresh.setEnabled(False)
self.ui.refresh.setText('loading')
self.ui.refresh.update()
threadData = threading.Thread(target=self.getData)
threadData.start()
#self.getData()
threadData.join()
for AP in self.listItemsAP:
item=QtGui.QTreeWidgetItem([AP[0],' '+str(AP[1])+'%',AP[2]])
if(AP[1]<=20):
icon=QtGui.QIcon("images/reception_wifi_1.gif")
if(AP[1]>20 and AP[1] <=40):
icon=QtGui.QIcon("images/reception_wifi_2.gif")
if(AP[1]>40 and AP[1] <=60):
icon=QtGui.QIcon("images/reception_wifi_3.gif")
if(AP[1]>60 and AP[1] <=80):
icon=QtGui.QIcon("images/reception_wifi_4.gif")
if(AP[1]>80):
icon=QtGui.QIcon("images/reception_wifi_5.gif")
self.ui.treeWidget.setIconSize(QtCore.QSize(40,40))
item.setIcon(1,icon)
if AP[1]!="":
self.ui.treeWidget.addTopLevelItem(item)
[docs] def getData(self):
"""
scan the AP
"""
nbAP= 0
self.scanner.scanForWifiNetworks()
APs=self.scanner.getWifiNetworksList()
print "number of AP :"+str(len(APs))
for AP in APs:
#print AP
signal=round(float(AP[5]),3)*100
itemAP=[AP[1],signal,AP[0]]
self.listItemsAP.append(itemAP)
self.ui.refresh.setEnabled(True)
self.ui.refresh.setText('refresh')
if __name__ == "__main__":
import sys
app= QtGui.QApplication(sys.argv)
scr = APControlor()
scr.show()
sys.exit(app.exec_())