2011-03-20 14:31:50 +07:00
# -*- coding: utf-8 -*-
# Relational
# Copyright (C) 2008 Salvo "LtWorf" Tomaselli
2013-12-26 17:16:12 +07:00
#
2011-03-20 14:31:50 +07:00
# Relational is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
2013-12-26 17:16:12 +07:00
#
2011-03-20 14:31:50 +07:00
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
2013-12-26 17:16:12 +07:00
#
2011-03-20 14:31:50 +07:00
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2013-12-26 17:16:12 +07:00
#
2011-03-20 14:31:50 +07:00
# author Salvo "LtWorf" Tomaselli <tiposchi@tiscali.it>
2013-12-26 17:16:12 +07:00
import sys
import os
import pickle
2011-10-08 13:32:31 +07:00
try :
from PyQt4 import QtCore , QtGui
except :
from PySide import QtCore , QtGui
2013-12-26 17:16:12 +07:00
2011-03-21 02:43:57 +07:00
from relational import relation , parser , optimizer , rtypes
2011-03-20 14:31:50 +07:00
import about
import survey
import surveyForm
import maingui
2011-10-08 13:32:31 +07:00
import compatibility
2011-03-20 14:31:50 +07:00
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
class relForm ( QtGui . QMainWindow ) :
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
def __init__ ( self , ui ) :
QtGui . QMainWindow . __init__ ( self )
self . About = None
self . Survey = None
self . relations = { } #Dictionary for relations
self . undo = None #UndoQueue for queries
self . selectedRelation = None
self . ui = ui
2011-03-22 08:28:41 +07:00
self . qcounter = 1 #Query counter
2013-12-26 17:16:12 +07:00
self . settings = QtCore . QSettings ( )
2011-06-14 11:21:15 +07:00
def checkVersion ( self ) :
from relational import maintenance
online = maintenance . check_latest_version ( )
2013-12-26 17:16:12 +07:00
2011-06-14 11:21:15 +07:00
if online > version :
r = QtGui . QApplication . translate ( " Form " , " New version available online: %s . " % online )
elif online == version :
r = QtGui . QApplication . translate ( " Form " , " Latest version installed. " )
else :
r = QtGui . QApplication . translate ( " Form " , " You are using an unstable version. " )
2013-12-26 17:16:12 +07:00
2011-06-14 11:21:15 +07:00
QtGui . QMessageBox . information ( self , QtGui . QApplication . translate ( " Form " , " Version " ) , r )
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
def load_query ( self , * index ) :
self . ui . txtQuery . setText ( self . savedQ . itemData ( index [ 0 ] ) . toString ( ) )
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
def undoOptimize ( self ) :
''' Undoes the optimization on the query, popping one item from the undo list '''
if self . undo != None :
self . ui . txtQuery . setText ( self . undo )
def optimize ( self ) :
''' Performs all the possible optimizations on the query '''
self . undo = self . ui . txtQuery . text ( ) #Storing the query in undo list
2013-12-26 17:16:12 +07:00
2011-10-08 17:35:24 +07:00
query = compatibility . get_py_str ( self . ui . txtQuery . text ( ) )
2011-10-15 17:30:31 +07:00
try :
result = optimizer . optimize_all ( query , self . relations )
compatibility . set_utf8_text ( self . ui . txtQuery , result )
except Exception , e :
QtGui . QMessageBox . information ( None , QtGui . QApplication . translate ( " Form " , " Error " ) , " %s \n %s " % ( QtGui . QApplication . translate ( " Form " , " Check your query! " ) , e . __str__ ( ) ) )
2013-12-26 17:16:12 +07:00
2011-03-20 16:18:30 +07:00
def resumeHistory ( self , item ) :
2011-10-08 13:32:31 +07:00
itm = compatibility . get_py_str ( item . text ( ) ) . split ( ' = ' , 1 )
compatibility . set_utf8_text ( self . ui . txtResult , itm [ 0 ] )
2013-12-26 17:16:12 +07:00
compatibility . set_utf8_text ( self . ui . txtQuery , itm [ 1 ] )
2011-03-20 14:31:50 +07:00
def execute ( self ) :
''' Executes the query '''
2013-12-26 17:16:12 +07:00
2011-10-08 13:32:31 +07:00
query = compatibility . get_py_str ( self . ui . txtQuery . text ( ) )
res_rel = compatibility . get_py_str ( self . ui . txtResult . text ( ) ) #result relation's name
2013-12-26 17:16:12 +07:00
2011-03-21 02:43:57 +07:00
if not rtypes . is_valid_relation_name ( res_rel ) :
QtGui . QMessageBox . information ( self , QtGui . QApplication . translate ( " Form " , " Error " ) , QtGui . QApplication . translate ( " Form " , " Wrong name for destination relation. " ) )
2011-03-20 16:18:30 +07:00
return
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
try :
#Converting string to utf8 and then from qstring to normal string
expr = parser . parse ( query ) #Converting expression to python code
print query , " --> " , expr #Printing debug
result = eval ( expr , self . relations ) #Evaluating the expression
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
self . relations [ res_rel ] = result #Add the relation to the dictionary
self . updateRelations ( ) #update the list
self . selectedRelation = result
self . showRelation ( self . selectedRelation ) #Show the result in the table
except Exception , e :
2011-11-01 13:47:03 +07:00
print e . __unicode__ ( )
QtGui . QMessageBox . information ( None , QtGui . QApplication . translate ( " Form " , " Error " ) , u " %s \n %s " % ( QtGui . QApplication . translate ( " Form " , " Check your query! " ) , e . __unicode__ ( ) ) )
2011-03-20 16:18:30 +07:00
return
2011-10-08 17:35:24 +07:00
#Adds to history
2011-10-15 17:30:31 +07:00
item = u ' %s = %s ' % ( compatibility . get_py_str ( self . ui . txtResult . text ( ) ) , compatibility . get_py_str ( self . ui . txtQuery . text ( ) ) )
2011-10-15 16:45:33 +07:00
#item=item.decode('utf-8'))
2011-10-08 17:35:24 +07:00
compatibility . add_list_item ( self . ui . lstHistory , item )
2013-12-26 17:16:12 +07:00
2011-03-20 16:18:30 +07:00
self . qcounter + = 1
2011-10-08 13:32:31 +07:00
compatibility . set_utf8_text ( self . ui . txtResult , u " _last %d " % self . qcounter ) #Sets the result relation name to none
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
def showRelation ( self , rel ) :
''' Shows the selected relation into the table '''
self . ui . table . clear ( )
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
if rel == None : #No relation to show
self . ui . table . setColumnCount ( 1 )
self . ui . table . headerItem ( ) . setText ( 0 , " Empty relation " )
return
self . ui . table . setColumnCount ( len ( rel . header . attributes ) )
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
#Set content
for i in rel . content :
item = QtGui . QTreeWidgetItem ( )
for j in range ( len ( i ) ) :
item . setText ( j , i [ j ] )
self . ui . table . addTopLevelItem ( item )
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
#Sets columns
for i in range ( len ( rel . header . attributes ) ) :
self . ui . table . headerItem ( ) . setText ( i , rel . header . attributes [ i ] )
self . ui . table . resizeColumnToContents ( i ) #Must be done in order to avoid too small columns
2013-12-26 17:16:12 +07:00
2011-03-20 16:49:02 +07:00
def printRelation ( self , item ) :
2011-10-08 13:32:31 +07:00
self . selectedRelation = self . relations [ compatibility . get_py_str ( item . text ( ) ) ]
2011-03-20 16:49:02 +07:00
self . showRelation ( self . selectedRelation )
2013-12-26 17:16:12 +07:00
2011-03-20 16:49:02 +07:00
def showAttributes ( self , item ) :
2011-03-20 14:31:50 +07:00
''' Shows the attributes of the selected relation '''
2011-10-08 13:32:31 +07:00
rel = compatibility . get_py_str ( item . text ( ) )
2011-03-20 16:49:02 +07:00
self . ui . lstAttributes . clear ( )
for j in self . relations [ rel ] . header . attributes :
self . ui . lstAttributes . addItem ( j )
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
def updateRelations ( self ) :
self . ui . lstRelations . clear ( )
for i in self . relations :
if i != " __builtins__ " :
self . ui . lstRelations . addItem ( i )
def saveRelation ( self ) :
2011-03-20 16:49:02 +07:00
filename = QtGui . QFileDialog . getSaveFileName ( self , QtGui . QApplication . translate ( " Form " , " Save Relation " ) , " " , QtGui . QApplication . translate ( " Form " , " Relations (*.csv) " ) )
2013-12-26 17:16:12 +07:00
filename = compatibility . get_filename ( filename )
2011-03-20 16:49:02 +07:00
if ( len ( filename ) == 0 ) : #Returns if no file was selected
return
self . selectedRelation . save ( filename )
2011-03-20 14:31:50 +07:00
return
def unloadRelation ( self ) :
for i in self . ui . lstRelations . selectedItems ( ) :
2011-10-08 13:32:31 +07:00
del self . relations [ compatibility . get_py_str ( i . text ( ) ) ]
2011-03-20 14:31:50 +07:00
self . updateRelations ( )
2011-10-13 12:06:24 +07:00
def editRelation ( self ) :
import creator
for i in self . ui . lstRelations . selectedItems ( ) :
2011-10-13 15:15:38 +07:00
result = creator . edit_relation ( self . relations [ compatibility . get_py_str ( i . text ( ) ) ] )
2011-10-13 13:44:20 +07:00
if result != None :
self . relations [ compatibility . get_py_str ( i . text ( ) ) ] = result
2011-10-13 12:06:24 +07:00
self . updateRelations ( )
def newRelation ( self ) :
import creator
2011-10-13 15:15:38 +07:00
result = creator . edit_relation ( )
2013-12-26 17:16:12 +07:00
2011-10-13 13:44:20 +07:00
if result == None :
return
res = QtGui . QInputDialog . getText (
2013-12-26 17:16:12 +07:00
self ,
2011-10-13 13:44:20 +07:00
QtGui . QApplication . translate ( " Form " , " New relation " ) ,
QtGui . QApplication . translate ( " Form " , " Insert the name for the new relation " ) ,
QtGui . QLineEdit . Normal , ' ' )
if res [ 1 ] == False or len ( res [ 0 ] ) == 0 :
return
2013-12-26 17:16:12 +07:00
2011-10-13 13:44:20 +07:00
#Patch provided by Angelo 'Havoc' Puglisi
name = compatibility . get_py_str ( res [ 0 ] )
2013-12-26 17:16:12 +07:00
2011-10-13 13:44:20 +07:00
if not rtypes . is_valid_relation_name ( name ) :
r = QtGui . QApplication . translate ( " Form " , str ( " Wrong name for destination relation: %s . " % name ) )
QtGui . QMessageBox . information ( self , QtGui . QApplication . translate ( " Form " , " Error " ) , r )
return
2013-12-26 17:16:12 +07:00
2011-10-13 13:44:20 +07:00
try :
self . relations [ name ] = result
except Exception , e :
print e
QtGui . QMessageBox . information ( None , QtGui . QApplication . translate ( " Form " , " Error " ) , " %s \n %s " % ( QtGui . QApplication . translate ( " Form " , " Check your query! " ) , e . __str__ ( ) ) )
return
2013-12-26 17:16:12 +07:00
2011-10-13 13:44:20 +07:00
self . updateRelations ( )
2013-12-26 17:16:12 +07:00
def closeEvent ( self , event ) :
self . save_settings ( )
event . accept ( )
def save_settings ( self ) :
#self.settings.setValue("width",)
pass
def restore_settings ( self ) :
#self.settings.value('session_name','default').toString()
pass
2011-10-13 13:44:20 +07:00
2011-03-20 14:31:50 +07:00
def showSurvey ( self ) :
if self . Survey == None :
self . Survey = surveyForm . surveyForm ( )
ui = survey . Ui_Form ( )
self . Survey . setUi ( ui )
ui . setupUi ( self . Survey )
self . Survey . setDefaultValues ( )
self . Survey . show ( )
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
def showAbout ( self ) :
if self . About == None :
self . About = QtGui . QDialog ( )
ui = about . Ui_Dialog ( )
ui . setupUi ( self . About )
self . About . show ( )
def loadRelation ( self , filename = None , name = None ) :
''' Loads a relation. Without parameters it will ask the user which relation to load,
otherwise it will load filename , giving it name .
It shouldn ' t be called giving filename but not giving name. ' ' '
#Asking for file to load
if filename == None :
2011-03-22 08:28:41 +07:00
filename = QtGui . QFileDialog . getOpenFileName ( self , QtGui . QApplication . translate ( " Form " , " Load Relation " ) , " " , QtGui . QApplication . translate ( " Form " , " Relations (*.csv);;Text Files (*.txt);;All Files (*) " ) )
2011-10-08 13:32:31 +07:00
filename = compatibility . get_filename ( filename )
2011-03-21 02:43:57 +07:00
2011-03-21 11:10:22 +07:00
#Default relation's name
f = filename . split ( ' / ' ) #Split the full path
2011-03-21 02:43:57 +07:00
defname = f [ len ( f ) - 1 ] . lower ( ) #Takes only the lowercase filename
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
if len ( defname ) == 0 :
return
2011-03-20 16:49:02 +07:00
2011-03-20 14:31:50 +07:00
if ( defname . endswith ( " .csv " ) ) : #removes the extension
defname = defname [ : - 4 ]
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
if name == None : #Prompt dialog to insert name for the relation
res = QtGui . QInputDialog . getText ( self , QtGui . QApplication . translate ( " Form " , " New relation " ) , QtGui . QApplication . translate ( " Form " , " Insert the name for the new relation " ) ,
QtGui . QLineEdit . Normal , defname )
if res [ 1 ] == False or len ( res [ 0 ] ) == 0 :
return
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
#Patch provided by Angelo 'Havoc' Puglisi
2011-10-08 13:32:31 +07:00
name = compatibility . get_py_str ( res [ 0 ] )
2013-12-26 17:16:12 +07:00
2011-04-01 02:06:08 +07:00
if not rtypes . is_valid_relation_name ( name ) :
2011-10-08 13:32:31 +07:00
r = QtGui . QApplication . translate ( " Form " , str ( " Wrong name for destination relation: %s . " % name ) )
QtGui . QMessageBox . information ( self , QtGui . QApplication . translate ( " Form " , " Error " ) , r )
2011-04-01 02:06:08 +07:00
return
2013-12-26 17:16:12 +07:00
2011-04-01 02:06:08 +07:00
try :
self . relations [ name ] = relation . relation ( filename )
except Exception , e :
print e
QtGui . QMessageBox . information ( None , QtGui . QApplication . translate ( " Form " , " Error " ) , " %s \n %s " % ( QtGui . QApplication . translate ( " Form " , " Check your query! " ) , e . __str__ ( ) ) )
return
2013-12-26 17:16:12 +07:00
2011-04-01 02:06:08 +07:00
self . updateRelations ( )
2011-03-21 11:10:22 +07:00
2011-03-20 14:31:50 +07:00
def addProduct ( self ) :
self . addSymbolInQuery ( u " * " )
def addDifference ( self ) :
self . addSymbolInQuery ( u " - " )
def addUnion ( self ) :
self . addSymbolInQuery ( u " ᑌ " )
def addIntersection ( self ) :
self . addSymbolInQuery ( u " ᑎ " )
def addDivision ( self ) :
self . addSymbolInQuery ( u " ÷ " )
def addOLeft ( self ) :
self . addSymbolInQuery ( u " ᐅLEFTᐊ " )
def addJoin ( self ) :
self . addSymbolInQuery ( u " ᐅᐊ " )
def addORight ( self ) :
self . addSymbolInQuery ( u " ᐅRIGHTᐊ " )
def addOuter ( self ) :
self . addSymbolInQuery ( u " ᐅFULLᐊ " )
def addProjection ( self ) :
self . addSymbolInQuery ( u " π " )
def addSelection ( self ) :
self . addSymbolInQuery ( u " σ " )
def addRename ( self ) :
self . addSymbolInQuery ( u " ρ " )
def addArrow ( self ) :
self . addSymbolInQuery ( u " ➡ " )
2013-12-26 17:16:12 +07:00
2011-03-20 14:31:50 +07:00
def addSymbolInQuery ( self , symbol ) :
self . ui . txtQuery . insert ( symbol )
self . ui . txtQuery . setFocus ( )