mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-27 00:33:48 -05:00
382 lines
15 KiB
Python
382 lines
15 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
/***************************************************************************
|
|
Name : DB Manager
|
|
Description : Database manager plugin for QGIS
|
|
Date : March 2015
|
|
copyright : (C) 2015 Hugo Mercier / Oslandia
|
|
email : hugo dot mercier at oslandia dot com
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* 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. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
Query builder dialog, based on the QSpatialite plugin (GPLv2+) by Romain Riviere
|
|
"""
|
|
|
|
from PyQt4.QtGui import *
|
|
from PyQt4.QtCore import *
|
|
|
|
from .ui.ui_DlgQueryBuilder import Ui_DbManagerQueryBuilderDlg as Ui_Dialog
|
|
from .db_plugins.plugin import VectorTable
|
|
|
|
class FocusEventFilter(QObject):
|
|
def __init__( self, parent ):
|
|
QObject.__init__( self, parent)
|
|
self.focus = ''
|
|
|
|
def eventFilter( self, obj, event ):
|
|
if event.type() == QEvent.FocusIn:
|
|
self.focus = obj.objectName()
|
|
return QObject.eventFilter( self, obj, event )
|
|
|
|
|
|
def insertWithSelection( widget, text ):
|
|
if widget.textCursor().hasSelection(): #user has selectedsomething...
|
|
selection=widget.textCursor().selectedText()
|
|
widget.insertPlainText(text+selection+")")
|
|
else:
|
|
widget.insertPlainText(text)
|
|
|
|
def insertWithSelectionOn( parent, objectname, text ):
|
|
"""Insert the text in a QTextEdit given by its objectname"""
|
|
w = parent.findChild( QTextEdit, objectname )
|
|
insertWithSelection( w, text )
|
|
|
|
class QueryBuilderDlg(QDialog):
|
|
|
|
# object used to store parameters between invocations
|
|
saveParameter = None
|
|
|
|
def __init__(self, iface, db, parent=None, reset = False):
|
|
QDialog.__init__(self, parent)
|
|
self.iface = iface
|
|
self.db = db
|
|
self.query = ''
|
|
self.ui = Ui_Dialog()
|
|
self.ui.setupUi(self)
|
|
self.ui.group.setMaximumHeight(self.ui.tab.sizeHint().height())
|
|
self.ui.order.setMaximumHeight(self.ui.tab.sizeHint().height())
|
|
|
|
self.evt = FocusEventFilter( self )
|
|
self.ui.col.installEventFilter( self.evt )
|
|
self.ui.where.installEventFilter( self.evt )
|
|
self.ui.group.installEventFilter( self.evt )
|
|
self.ui.order.installEventFilter( self.evt )
|
|
|
|
d = self.db.connector.getQueryBuilderDictionary()
|
|
#Application default parameters
|
|
self.table=None
|
|
self.col_col=[]
|
|
self.col_where=[]
|
|
self.coltables=[]
|
|
self.ui.extract.setChecked(True)
|
|
#ComboBox default values
|
|
self.ui.functions.insertItems(1,d['function'])
|
|
self.ui.math.insertItems(1,d['math'])
|
|
self.ui.aggregates.insertItems(1,d['aggregate'])
|
|
self.ui.operators.insertItems(1,d['operator'])
|
|
self.ui.stringfct.insertItems(1,d['string'])
|
|
#self.ui.Rtree.insertItems(1,rtreecommand)
|
|
|
|
# restore last query if needed
|
|
if reset:
|
|
QueryBuilderDlg.saveParameter = None
|
|
if QueryBuilderDlg.saveParameter is not None:
|
|
self.restoreLastQuery()
|
|
|
|
#Show Tables
|
|
self.show_tables()
|
|
|
|
#Signal/slot
|
|
QObject.connect(self.ui.aggregates,SIGNAL("currentIndexChanged(const QString&)"),self.add_aggregate)
|
|
QObject.connect(self.ui.stringfct,SIGNAL("currentIndexChanged(const QString&)"),self.add_stringfct)
|
|
QObject.connect(self.ui.operators,SIGNAL("currentIndexChanged(const QString&)"),self.add_operators)
|
|
QObject.connect(self.ui.functions,SIGNAL("currentIndexChanged(const QString&)"),self.add_functions)
|
|
QObject.connect(self.ui.math,SIGNAL("currentIndexChanged(const QString&)"),self.add_math)
|
|
QObject.connect(self.ui.tables,SIGNAL("currentIndexChanged(const QString&)"),self.add_tables)
|
|
QObject.connect(self.ui.tables,SIGNAL("currentIndexChanged(const QString&)"),self.list_cols)
|
|
QObject.connect(self.ui.columns,SIGNAL("currentIndexChanged(const QString&)"),self.add_columns)
|
|
QObject.connect(self.ui.columns_2,SIGNAL("currentIndexChanged(const QString&)"),self.list_values)
|
|
QObject.connect(self.ui.reset,SIGNAL("clicked(bool)"),self.reset)
|
|
QObject.connect(self.ui.extract,SIGNAL("stateChanged(int)"),self.list_values)
|
|
QObject.connect(self.ui.values,SIGNAL("doubleClicked(const QModelIndex &)"),self.query_item)
|
|
QObject.connect(self.ui.buttonBox,SIGNAL("accepted()"),self.validate)
|
|
QObject.connect(self.ui.checkBox,SIGNAL("stateChanged(int)"),self.show_tables)
|
|
|
|
if self.db.explicitSpatialIndex():
|
|
self.tablesGeo=[table for table in self.tables if isinstance(table,VectorTable)]
|
|
tablesGeo=[ '"%s"."%s"'%(table.name,table.geomColumn) for table in self.tablesGeo]
|
|
self.ui.table_target.insertItems(1,tablesGeo)
|
|
self.idxTables=[table for table in self.tablesGeo if table.hasSpatialIndex()]
|
|
idxTables=['"%s"."%s"'%(table.name,table.geomColumn) for table in self.idxTables]
|
|
self.ui.table_idx.insertItems(1,idxTables)
|
|
|
|
QObject.connect(self.ui.usertree,SIGNAL("clicked(bool)"),self.use_rtree)
|
|
else:
|
|
self.ui.toolBox.setItemEnabled(2, False )
|
|
|
|
|
|
def update_table_list( self ):
|
|
self.tables = []
|
|
add_sys_tables = self.ui.checkBox.isChecked()
|
|
schemas = self.db.schemas()
|
|
if schemas is None:
|
|
self.tables = self.db.tables( None, add_sys_tables )
|
|
else:
|
|
for schema in schemas:
|
|
self.tables += self.db.tables(schema, add_sys_tables)
|
|
|
|
def show_tables(self):
|
|
self.update_table_list()
|
|
self.ui.tables.clear()
|
|
self.ui.tables.insertItems(0,["Tables"])
|
|
self.ui.tables.insertItems(1,[t.name for t in self.tables])
|
|
|
|
def add_aggregate(self):
|
|
if self.ui.aggregates.currentIndex() <= 0:
|
|
return
|
|
ag=self.ui.aggregates.currentText()
|
|
|
|
insertWithSelection( self.ui.col, ag )
|
|
|
|
self.ui.aggregates.setCurrentIndex(0)
|
|
|
|
def add_functions(self):
|
|
if self.ui.functions.currentIndex() <= 0:
|
|
return
|
|
ag=self.ui.functions.currentText()
|
|
|
|
insertWithSelectionOn( self, self.evt.focus, ag )
|
|
|
|
self.ui.functions.setCurrentIndex(0)
|
|
|
|
|
|
|
|
def add_stringfct(self):
|
|
if self.ui.stringFct.currentIndex() <= 0:
|
|
return
|
|
ag=self.ui.stringfct.currentText()
|
|
|
|
insertWithSelectionOn( self, self.evt.focus, ag )
|
|
|
|
self.ui.stringfct.setCurrentIndex(0)
|
|
|
|
def add_math(self):
|
|
if self.ui.math.currentIndex() <= 0:
|
|
return
|
|
ag=self.ui.math.currentText()
|
|
|
|
insertWithSelectionOn( self, self.evt.focus, ag )
|
|
|
|
self.ui.math.setCurrentIndex(0)
|
|
|
|
def add_operators(self):
|
|
if self.ui.operators.currentIndex() <= 0:
|
|
return
|
|
ag=self.ui.operators.currentText()
|
|
|
|
if self.evt.focus == "where": # in where section
|
|
self.ui.where.insertPlainText(ag)
|
|
else:
|
|
self.ui.col.insertPlainText(ag)
|
|
self.ui.operators.setCurrentIndex(0)
|
|
|
|
def add_tables(self):
|
|
if self.ui.tables.currentIndex() <= 0:
|
|
return
|
|
ag=self.ui.tables.currentText()
|
|
#Retrieve Table Object from txt
|
|
tableObj=[table for table in self.tables if table.name.upper()==ag.upper()]
|
|
if len(tableObj)!=1:
|
|
return #No object with this name
|
|
self.table=tableObj[0]
|
|
if (ag in self.coltables): #table already use
|
|
reponse=QMessageBox.question(self, "Table already used","Do you want to add table %s again ?"%ag, QMessageBox.Yes | QMessageBox.No)
|
|
if reponse==QMessageBox.No:
|
|
return
|
|
ag = self.table.quotedName()
|
|
txt=self.ui.tab.text()
|
|
if (txt is None) or (txt in (""," ")):
|
|
self.ui.tab.setText('%s'%ag)
|
|
else:
|
|
self.ui.tab.setText('%s, %s'%(txt,ag))
|
|
self.ui.tables.setCurrentIndex(0)
|
|
|
|
def add_columns(self):
|
|
if self.ui.columns.currentIndex() <= 0:
|
|
return
|
|
ag=self.ui.columns.currentText()
|
|
if self.evt.focus == "where": # in where section
|
|
if ag in self.col_where: # column already called in where section
|
|
reponse=QMessageBox.question(self, "Column already used in WHERE clause","Do you want to add column %s again ?"%ag, QMessageBox.Yes | QMessageBox.No)
|
|
if reponse==QMessageBox.No:
|
|
self.ui.columns.setCurrentIndex(0)
|
|
return
|
|
self.ui.where.insertPlainText(ag)
|
|
self.col_where.append(ag)
|
|
elif self.evt.focus == "col" :
|
|
if ag in self.col_col: # column already called in col section
|
|
reponse=QMessageBox.question(self, "Column already used in COLUMNS section","Do you want to add column %s again ?"%ag, QMessageBox.Yes | QMessageBox.No)
|
|
if reponse==QMessageBox.No:
|
|
self.ui.columns.setCurrentIndex(0)
|
|
return
|
|
if len(self.ui.col.toPlainText().strip()) > 0:
|
|
self.ui.col.insertPlainText(",\n" + ag)
|
|
else:
|
|
self.ui.col.insertPlainText(ag)
|
|
self.col_col.append(ag)
|
|
elif self.evt.focus == "group":
|
|
if len(self.ui.group.toPlainText().strip()) > 0:
|
|
self.ui.group.insertPlainText( ", " + ag )
|
|
else:
|
|
self.ui.group.insertPlainText( ag )
|
|
elif self.evt.focus == "order":
|
|
if len(self.ui.order.toPlainText().strip()) > 0:
|
|
self.ui.order.insertPlainText( ", " + ag )
|
|
else:
|
|
self.ui.order.insertPlainText( ag )
|
|
|
|
self.ui.columns.setCurrentIndex(0)
|
|
|
|
def list_cols(self):
|
|
table=self.table
|
|
if (table is None):
|
|
return
|
|
if (table.name in self.coltables):
|
|
return
|
|
|
|
columns=['"%s"."%s"'%(table.name,col.name) for col in table.fields()]
|
|
#add special '*' column:
|
|
columns=['"%s".*'%table.name]+columns
|
|
self.coltables.append(table.name) #table columns have been listed
|
|
# first and second col combobox
|
|
end=self.ui.columns.count()
|
|
self.ui.columns.insertItems(end,columns)
|
|
self.ui.columns_2.insertItems(end,columns)
|
|
end=self.ui.columns.count()
|
|
self.ui.columns.insertSeparator(end)
|
|
self.ui.columns_2.insertSeparator(end)
|
|
|
|
def list_values(self):
|
|
if self.ui.columns_2.currentIndex() <= 0:
|
|
return
|
|
item=self.ui.columns_2.currentText()
|
|
#recover column and table:
|
|
column=item.split(".") # "table".'column'
|
|
table=column[0]
|
|
if column[1]=='*':
|
|
return
|
|
table = table[1:-1]
|
|
|
|
qtable = [t for t in self.tables if t.name.lower() == table.lower()][0].quotedName()
|
|
|
|
if self.ui.extract.isChecked():
|
|
limit = 10
|
|
else:
|
|
limit = None
|
|
model = self.db.columnUniqueValuesModel( item, qtable, limit )
|
|
self.ui.values.setModel(model)
|
|
|
|
def query_item(self, index):
|
|
queryWord = index.data()
|
|
queryWord=' "%s"' %queryWord
|
|
if queryWord != '':
|
|
self.ui.where.insertPlainText(queryWord)
|
|
self.ui.where.setFocus()
|
|
|
|
def use_rtree(self):
|
|
idx=self.ui.table_idx.currentText()
|
|
if idx in (None,""," ","Table (with Spatial Index)"):
|
|
return
|
|
try:
|
|
tab_idx=idx.split(".")[0][1:-1] #remove "
|
|
col_idx=idx.split(".")[1][1:-1] #remove '
|
|
except:
|
|
pop_up_error("All fields are necessary",self)
|
|
tgt=self.ui.table_target.currentText()
|
|
if tgt in (None,""," ","Table (Target)"):
|
|
return
|
|
tgt_tab = tgt.split('.')[0][1:-1]
|
|
tgt_col = tgt.split('.')[1][1:-1]
|
|
sql=""
|
|
if self.ui.where.toPlainText() not in (None,""," "):
|
|
sql+="\nAND"
|
|
sql+=self.db.spatialIndexClause( tab_idx, col_idx, tgt_tab, tgt_col )
|
|
self.ui.where.insertPlainText(sql)
|
|
|
|
def reset(self):
|
|
#reset lists:
|
|
self.ui.values.setModel(None)
|
|
self.ui.columns_2.clear()
|
|
self.ui.columns.insertItems(0,["Columns"])
|
|
self.ui.columns_2.insertItems(0,["Columns"])
|
|
self.coltables=[]
|
|
self.col_col=[]
|
|
self.col_where=[]
|
|
|
|
def validate(self):
|
|
query_col=unicode(self.ui.col.toPlainText())
|
|
query_table=unicode(self.ui.tab.text())
|
|
query_where=unicode(self.ui.where.toPlainText())
|
|
query_group=unicode(self.ui.group.toPlainText())
|
|
query_order=unicode(self.ui.order.toPlainText())
|
|
query=""
|
|
if query_col.strip()!='':
|
|
query+="SELECT %s \nFROM %s"%(query_col,query_table)
|
|
if query_where.strip()!='':
|
|
query+="\nWHERE %s"%query_where
|
|
if query_group.strip()!='':
|
|
query+="\nGROUP BY %s"%query_group
|
|
if query_order.strip()!='':
|
|
query+="\nORDER BY %s"%query_order
|
|
if query == '':
|
|
return
|
|
self.query = query
|
|
|
|
saveParameter = {}
|
|
saveParameter["coltables"]=self.coltables
|
|
saveParameter["col_col"]=self.col_col
|
|
saveParameter["col_where"]=self.col_where
|
|
saveParameter["col"]=query_col
|
|
saveParameter["tab"]=query_table
|
|
saveParameter["where"]=query_where
|
|
saveParameter["group"]=query_group
|
|
saveParameter["order"]=query_order
|
|
QueryBuilderDlg.saveParameter = saveParameter
|
|
|
|
def restoreLastQuery(self):
|
|
self.update_table_list()
|
|
|
|
saveParameter = QueryBuilderDlg.saveParameter
|
|
self.coltables=saveParameter["coltables"]
|
|
self.col_col=saveParameter["col_col"]
|
|
self.col_where=saveParameter["col_where"]
|
|
self.ui.col.insertPlainText(saveParameter["col"])
|
|
self.ui.tab.setText(saveParameter["tab"])
|
|
self.ui.where.insertPlainText(saveParameter["where"])
|
|
self.ui.order.setPlainText(saveParameter["order"])
|
|
self.ui.group.setPlainText(saveParameter["group"])
|
|
#list previous colist:
|
|
for tablename in self.coltables:
|
|
#Retrieve table object from table name:
|
|
table=[table for table in self.tables if table.name.upper()==tablename.upper()]
|
|
if len(table)!=1:
|
|
break
|
|
table=table[0]
|
|
columns=['"%s"."%s"'%(table.name,col.name) for col in table.fields()]
|
|
# first and second col combobox
|
|
end=self.ui.columns.count()
|
|
self.ui.columns.insertItems(end,columns)
|
|
self.ui.columns_2.insertItems(end,columns)
|
|
end=self.ui.columns.count()
|
|
self.ui.columns.insertSeparator(end)
|
|
self.ui.columns_2.insertSeparator(end)
|