2011-03-20 14:31:50 +07:00
# -*- coding: utf-8 -*-
# Relational
# Copyright (C) 2008 Salvo "LtWorf" Tomaselli
#
# 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.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# author Salvo "LtWorf" Tomaselli <tiposchi@tiscali.it>
from PyQt4 import QtCore , QtGui
2011-03-21 02:43:57 +07:00
from relational import relation , parser , optimizer , rtypes
2011-03-20 14:31:50 +07:00
import sys
import about
import survey
import os
import surveyForm
import maingui
class relForm ( QtGui . QMainWindow ) :
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
2011-06-14 11:21:15 +07:00
def checkVersion ( self ) :
from relational import maintenance
online = maintenance . check_latest_version ( )
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. " )
QtGui . QMessageBox . information ( self , QtGui . QApplication . translate ( " Form " , " Version " ) , r )
2011-03-20 14:31:50 +07:00
def load_query ( self , * index ) :
self . ui . txtQuery . setText ( self . savedQ . itemData ( index [ 0 ] ) . toString ( ) )
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
result = optimizer . optimize_all ( str ( self . ui . txtQuery . text ( ) . toUtf8 ( ) ) , self . relations )
self . ui . txtQuery . setText ( QtCore . QString . fromUtf8 ( result ) )
2011-03-20 16:18:30 +07:00
def resumeHistory ( self , item ) :
2011-03-20 18:23:20 +07:00
itm = str ( item . text ( ) . toUtf8 ( ) ) . split ( ' = ' , 1 )
self . ui . txtResult . setText ( QtCore . QString . fromUtf8 ( itm [ 0 ] ) )
self . ui . txtQuery . setText ( QtCore . QString . fromUtf8 ( itm [ 1 ] ) )
2011-03-20 16:18:30 +07:00
2011-03-20 14:31:50 +07:00
def execute ( self ) :
''' Executes the query '''
2011-03-20 16:18:30 +07:00
query = str ( self . ui . txtQuery . text ( ) . toUtf8 ( ) )
2011-03-21 11:10:22 +07:00
res_rel = str ( self . ui . txtResult . text ( ) . toUtf8 ( ) ) #result relation's name
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
2011-03-21 02:43:57 +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
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 :
print e
QtGui . QMessageBox . information ( None , QtGui . QApplication . translate ( " Form " , " Error " ) , " %s \n %s " % ( QtGui . QApplication . translate ( " Form " , " Check your query! " ) , e . __str__ ( ) ) )
2011-03-20 16:18:30 +07:00
return
#Query was executed normally
history_item = QtCore . QString ( )
history_item . append ( self . ui . txtResult . text ( ) )
history_item . append ( u ' = ' )
history_item . append ( self . ui . txtQuery . text ( ) )
2011-03-20 16:49:02 +07:00
hitem = QtGui . QListWidgetItem ( None , 0 )
hitem . setText ( history_item )
self . ui . lstHistory . addItem ( hitem )
self . ui . lstHistory . setCurrentItem ( hitem )
2011-03-20 16:18:30 +07:00
self . qcounter + = 1
self . ui . txtResult . setText ( QtCore . QString ( u " _last %d " % self . qcounter ) ) #Sets the result relation name to none
2011-03-20 14:31:50 +07:00
def showRelation ( self , rel ) :
''' Shows the selected relation into the table '''
self . ui . table . clear ( )
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 ) )
#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 )
#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
2011-03-20 16:49:02 +07:00
def printRelation ( self , item ) :
self . selectedRelation = self . relations [ str ( item . text ( ) . toUtf8 ( ) ) ]
self . showRelation ( self . selectedRelation )
2011-03-20 14:31:50 +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-03-20 16:49:02 +07:00
rel = str ( item . text ( ) . toUtf8 ( ) )
self . ui . lstAttributes . clear ( )
for j in self . relations [ rel ] . header . attributes :
self . ui . lstAttributes . addItem ( j )
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) " ) )
2011-03-20 14:31:50 +07:00
2011-03-20 16:49:02 +07:00
filename = str ( filename . toUtf8 ( ) ) #Converts QString to string
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 ( ) :
del self . relations [ str ( i . text ( ) . toUtf8 ( ) ) ]
self . updateRelations ( )
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 ( )
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-03-21 11:10:22 +07:00
filename = str ( filename . toUtf8 ( ) )
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
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 ]
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
#Patch provided by Angelo 'Havoc' Puglisi
2011-03-21 02:43:57 +07:00
name = str ( res [ 0 ] . toUtf8 ( ) )
2011-04-01 02:06:08 +07:00
if not rtypes . is_valid_relation_name ( name ) :
2011-03-21 02:43:57 +07:00
QtGui . QMessageBox . information ( self , QtGui . QApplication . translate ( " Form " , " Error " ) , QtGui . QApplication . translate ( " Form " , " Wrong name for destination relation: %s . " % name ) )
2011-04-01 02:06:08 +07:00
return
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
self . updateRelations ( )
2011-03-21 11:10:22 +07:00
2011-03-20 14:31:50 +07:00
def insertTuple ( self ) :
''' Shows an input dialog and inserts the inserted tuple into the selected relation '''
res = QtGui . QInputDialog . getText ( self , QtGui . QApplication . translate ( " Form " , " New relation " ) , QtGui . QApplication . translate ( " Form " , " Insert the values, comma separated " ) ,
QtGui . QLineEdit . Normal , " " )
if res [ 1 ] == False :
return
t = [ ]
for i in str ( res [ 0 ] . toUtf8 ( ) ) . split ( " , " ) :
t . append ( i . strip ( ) )
if self . selectedRelation != None and self . selectedRelation . insert ( t ) > 0 :
self . showRelation ( self . selectedRelation )
return
def deleteTuple ( self ) :
''' Shows an input dialog and removes the tuples corresponding to the condition. '''
res = QtGui . QInputDialog . getText ( self , QtGui . QApplication . translate ( " Form " , " New relation " ) , QtGui . QApplication . translate ( " Form " , " Remove tuples: insert where condition " ) ,
QtGui . QLineEdit . Normal , " " )
if res [ 1 ] == False :
return
if self . selectedRelation != None and self . selectedRelation . delete ( str ( res [ 0 ] . toUtf8 ( ) ) ) > 0 :
self . showRelation ( self . selectedRelation )
return
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 " ➡ " )
def addSymbolInQuery ( self , symbol ) :
self . ui . txtQuery . insert ( symbol )
self . ui . txtQuery . setFocus ( )
2011-03-21 02:43:57 +07:00