diff --git a/CHANGELOG b/CHANGELOG index fc23812..6fb9dfa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,8 @@ - Better tokenizer, gives more indicative errors - Parser gives more indicative errors - Improved select_union_intersect_subtract optimization to avoid parenthesis whenever possible +- Moved feedback service, and added the code for it +- Different way of checking the latest version 1.1 - Incorrect relational operations now raise an exception instead of returning None diff --git a/feedback-ltworf/app.yaml b/feedback-ltworf/app.yaml index 7730430..475cb68 100644 --- a/feedback-ltworf/app.yaml +++ b/feedback-ltworf/app.yaml @@ -1,7 +1,7 @@ application: feedback-ltworf -version: 2 +version: 1 runtime: python27 -api_version: 1 +api_version: 3 threadsafe: true handlers: diff --git a/feedback-ltworf/feedback.py b/feedback-ltworf/feedback.py index fe644ca..b04c96a 100644 --- a/feedback-ltworf/feedback.py +++ b/feedback-ltworf/feedback.py @@ -9,16 +9,22 @@ application = micro_webapp2.WSGIApplication() def m(request, *args, **kwargs): return "" +@application.route("/version/") +def show_version(request, *args, **kwargs): + if kwargs["id"] == "relational": + return "1.2" + return "No version" + @application.route('/feedback/') def mail_sender(request, *args, **kwargs): - + if request.method != "POST": return "" - + message = "" for k,v in request.POST.iteritems(): message += "%s: %s\n" % (k,v) - + if kwargs["id"] == "relational": from google.appengine.api import mail diff --git a/relational/maintenance.py b/relational/maintenance.py index 00fba92..2231f8a 100644 --- a/relational/maintenance.py +++ b/relational/maintenance.py @@ -1,20 +1,20 @@ # -*- coding: utf-8 -*- # Relational # Copyright (C) 2008 Salvo "LtWorf" Tomaselli -# +# # Relation 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 . -# +# # author Salvo "LtWorf" Tomaselli # # Stuff non-related to relational algebra, but used for maintenance. @@ -26,7 +26,7 @@ import relation def send_survey(data): '''Sends the survey. Data must be a dictionary. returns the http response''' - + post='' for i in data.keys(): post+='%s: %s\n' %(i,data[i]) @@ -36,11 +36,11 @@ def send_survey(data): headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"} #connection = httplib.HTTPConnection('galileo.dmi.unict.it') #connection.request("POST","/~ltworf/survey.php",params,headers) - + connection = httplib.HTTPConnection('feedback-ltworf.appspot.com') connection.request("POST","/feedback/relational",params,headers) - - + + return connection.getresponse() @@ -48,54 +48,48 @@ def check_latest_version(): '''Returns the latest version available. Heavely dependent on server and server configurations not granted to work forever.''' - connection = httplib.HTTPConnection('galileo.dmi.unict.it') - connection.request("GET","/svn/relational/tags/") + connection = httplib.HTTPConnection('feedback-ltworf.appspot.com') + connection.request("GET","/version/relational") r=connection.getresponse() - + #html s=r.read() if len(s)==0: return None - - l= s[s.find('
    ')+4:s.find('
')].split('\n') - l.sort() - a=l[len(l)-1] - - s=a.find('"')+1 - return a[s:a.find('"',s)-1] + return s.strip() + class interface (object): '''It is used to provide services to the user interfaces, in order to reduce the amount of duplicated code present in different user interfaces. ''' - + def __init__(self): self.rels= {} - + def load(self,filename,name): '''Loads a relation from file, and gives it a name to be used in subsequent queries.''' pass - + def unload(self,name): '''Unloads an existing relation.''' pass - + def store(self,filename,name): '''Stores a relation to file.''' pass - + def get_relation(self,name): '''Returns the relation corresponding to name.''' pass - + def set_relation(self,name,rel): '''Sets the relation corresponding to name.''' pass - + def execute(self,query,relname='last_'): '''Executes a query, returns the result and if relname is not None, adds the result to the dictionary, with the name given in relname.''' pass - \ No newline at end of file diff --git a/relational_gui.py b/relational_gui.py index eaf4f16..0d31a63 100755 --- a/relational_gui.py +++ b/relational_gui.py @@ -112,6 +112,8 @@ if __name__ == "__main__": guihandler.version=version app = QtGui.QApplication(sys.argv) + app.setOrganizationName('None'); + app.setApplicationName('relational'); ui = maingui.Ui_MainWindow() Form = guihandler.relForm(ui) @@ -120,6 +122,7 @@ if __name__ == "__main__": Form.setFont(QtGui.QFont("Dejavu Sans Bold")) ui.setupUi(Form) + Form.restore_settings() for i in range(len(files)): if not os.path.isfile(files[i]): diff --git a/relational_gui/guihandler.py b/relational_gui/guihandler.py index e4bf626..125a801 100644 --- a/relational_gui/guihandler.py +++ b/relational_gui/guihandler.py @@ -1,38 +1,43 @@ # -*- 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 . -# +# # author Salvo "LtWorf" Tomaselli +import sys +import os +import pickle + try: from PyQt4 import QtCore, QtGui except: from PySide import QtCore, QtGui - + + + from relational import relation, parser, optimizer,rtypes -import sys import about import survey -import os import surveyForm import maingui import compatibility + class relForm(QtGui.QMainWindow): - + def __init__(self,ui): QtGui.QMainWindow.__init__(self) self.About=None @@ -42,23 +47,26 @@ class relForm(QtGui.QMainWindow): self.selectedRelation=None self.ui=ui self.qcounter=1 #Query counter + + self.settings = QtCore.QSettings() + 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) - - + + 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: @@ -67,37 +75,37 @@ class relForm(QtGui.QMainWindow): def optimize(self): '''Performs all the possible optimizations on the query''' self.undo=self.ui.txtQuery.text() #Storing the query in undo list - + query=compatibility.get_py_str(self.ui.txtQuery.text()) 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__()) ) - - - + + + def resumeHistory(self,item): itm=compatibility.get_py_str(item.text()).split(' = ',1) compatibility.set_utf8_text(self.ui.txtResult,itm[0]) - compatibility.set_utf8_text(self.ui.txtQuery,itm[1]) - + compatibility.set_utf8_text(self.ui.txtQuery,itm[1]) + def execute(self): '''Executes the query''' - + query=compatibility.get_py_str(self.ui.txtQuery.text()) res_rel=compatibility.get_py_str(self.ui.txtResult.text())#result relation's name - + 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.")) return - + 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 @@ -111,44 +119,44 @@ class relForm(QtGui.QMainWindow): item=u'%s = %s' % (compatibility.get_py_str(self.ui.txtResult.text()),compatibility.get_py_str(self.ui.txtQuery.text())) #item=item.decode('utf-8')) compatibility.add_list_item(self.ui.lstHistory,item) - + self.qcounter+=1 compatibility.set_utf8_text(self.ui.txtResult,u"_last%d"% self.qcounter) #Sets the result relation name to none - + 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 - - + + def printRelation(self,item): self.selectedRelation=self.relations[compatibility.get_py_str(item.text())] self.showRelation(self.selectedRelation) - + def showAttributes(self,item): '''Shows the attributes of the selected relation''' rel=compatibility.get_py_str(item.text()) self.ui.lstAttributes.clear() for j in self.relations[rel].header.attributes: self.ui.lstAttributes.addItem (j) - + def updateRelations(self): self.ui.lstRelations.clear() for i in self.relations: @@ -156,8 +164,8 @@ class relForm(QtGui.QMainWindow): self.ui.lstRelations.addItem(i) def saveRelation(self): filename = QtGui.QFileDialog.getSaveFileName(self,QtGui.QApplication.translate("Form", "Save Relation"),"",QtGui.QApplication.translate("Form", "Relations (*.csv)")) - - filename=compatibility.get_filename(filename) + + filename=compatibility.get_filename(filename) if (len(filename)==0):#Returns if no file was selected return self.selectedRelation.save(filename) @@ -176,36 +184,45 @@ class relForm(QtGui.QMainWindow): def newRelation(self): import creator result=creator.edit_relation() - + if result==None: return res=QtGui.QInputDialog.getText( - self, + self, 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 - + #Patch provided by Angelo 'Havoc' Puglisi name=compatibility.get_py_str(res[0]) - + 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 - + 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 - - - self.updateRelations() - + + self.updateRelations() + 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 + def showSurvey(self): if self.Survey==None: self.Survey=surveyForm.surveyForm() @@ -214,6 +231,7 @@ class relForm(QtGui.QMainWindow): ui.setupUi(self.Survey) self.Survey.setDefaultValues() self.Survey.show() + def showAbout(self): if self.About==None: self.About = QtGui.QDialog() @@ -233,35 +251,35 @@ class relForm(QtGui.QMainWindow): #Default relation's name f=filename.split('/') #Split the full path defname=f[len(f)-1].lower() #Takes only the lowercase filename - + if len(defname)==0: return 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 name=compatibility.get_py_str(res[0]) - + 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 - + 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() def addProduct(self): @@ -290,8 +308,7 @@ class relForm(QtGui.QMainWindow): self.addSymbolInQuery(u"ρ") def addArrow(self): self.addSymbolInQuery(u"➡") - + def addSymbolInQuery(self,symbol): self.ui.txtQuery.insert(symbol) self.ui.txtQuery.setFocus() - \ No newline at end of file