QGIS/python/plugins/db_manager/dlg_create_table.py

320 lines
9.8 KiB
Python

# -*- coding: utf-8 -*-
"""
/***************************************************************************
Name : DB Manager
Description : Database manager plugin for QuantumGIS
Date : Oct 13, 2011
copyright : (C) 2011 by Giuseppe Sucameli
email : brush.tyler@gmail.com
The content of this file is based on
- PG_Manager by Martin Dobias (GPLv2 license)
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
"""
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from .db_plugins.data_model import TableFieldsModel
from .db_plugins.plugin import DbError, ConnectionError
from .dlg_db_error import DlgDbError
from .ui.ui_DlgCreateTable import Ui_DlgCreateTable
class TableFieldsDelegate(QItemDelegate):
""" delegate with some special item editors """
def __init__(self, field_types, parent=None):
QItemDelegate.__init__(self, parent)
self.fieldTypes = field_types
def createEditor(self, parent, option, index):
# special combobox for field type
if index.column() == 1:
cbo = QComboBox(parent)
cbo.setEditable(True)
cbo.setAutoCompletion(True)
cbo.setFrame(False)
for item in self.fieldTypes:
cbo.addItem(item)
return cbo
elif index.column() == 2:
return QCheckBox(parent)
return QItemDelegate.createEditor(self, parent, option, index)
def setEditorData(self, editor, index):
""" load data from model to editor """
m = index.model()
if index.column() == 1:
txt = m.data(index, Qt.DisplayRole).toString()
editor.setEditText(txt)
elif index.column() == 2:
checked = m.data(index, Qt.DisplayRole).toBool()
editor.setChecked( checked )
else:
# use default
QItemDelegate.setEditorData(self, editor, index)
def setModelData(self, editor, model, index):
""" save data from editor back to model """
if index.column() == 1:
model.setData(index, QVariant(editor.currentText()))
elif index.column() == 1:
model.setData(index, QVariant(editor.isChecked()))
else:
# use default
QItemDelegate.setModelData(self, editor, model, index)
if index.column() == 0:
self.emit(SIGNAL("columnNameChanged()"))
class DlgCreateTable(QDialog, Ui_DlgCreateTable):
GEOM_TYPES = ["POINT", "LINESTRING", "POLYGON", "MULTIPOINT", "MULTILINESTRING", "MULTIPOLYGON", "GEOMETRYCOLLECTION"]
def __init__(self, item, parent=None):
QDialog.__init__(self, parent)
self.item = item
self.setupUi(self)
self.db = self.item.database()
self.schemas = self.db.schemas()
self.hasSchemas = self.schemas != None
self.fieldTypes = self.db.connector.fieldTypes()
m = TableFieldsModel(self, True) # it's editable
self.fields.setModel(m)
self.fields.setColumnHidden(3, True) # hide Default column
d = TableFieldsDelegate(self.fieldTypes, self)
self.fields.setItemDelegate(d)
self.fields.setColumnWidth(0,140)
self.fields.setColumnWidth(1,140)
self.fields.setColumnWidth(2,50)
b = QPushButton("&Create")
self.buttonBox.addButton(b, QDialogButtonBox.ActionRole)
self.connect(self.btnAddField, SIGNAL("clicked()"), self.addField)
self.connect(self.btnDeleteField, SIGNAL("clicked()"), self.deleteField)
self.connect(self.btnFieldUp, SIGNAL("clicked()"), self.fieldUp)
self.connect(self.btnFieldDown, SIGNAL("clicked()"), self.fieldDown)
self.connect(b, SIGNAL("clicked()"), self.createTable)
self.connect(self.chkGeomColumn, SIGNAL("clicked()"), self.updateUi)
self.connect(self.fields.selectionModel(), SIGNAL("selectionChanged(const QItemSelection &, const QItemSelection &)"), self.updateUiFields)
self.connect(d, SIGNAL("columnNameChanged()"), self.updatePkeyCombo)
self.populateSchemas()
self.updateUi()
self.updateUiFields()
def populateSchemas(self):
self.cboSchema.clear()
if not self.hasSchemas:
self.hideSchemas()
return
index = -1
for schema in self.schemas:
self.cboSchema.addItem(schema.name)
if hasattr(self.item, 'schema') and schema.name == self.item.schema().name:
index = self.cboSchema.count()-1
self.cboSchema.setCurrentIndex(index)
def hideSchemas(self):
self.cboSchema.setEnabled(False)
def updateUi(self):
useGeom = self.chkGeomColumn.isChecked()
self.cboGeomType.setEnabled(useGeom)
self.editGeomColumn.setEnabled(useGeom)
self.spinGeomDim.setEnabled(useGeom)
self.editGeomSrid.setEnabled(useGeom)
self.chkSpatialIndex.setEnabled(useGeom)
def updateUiFields(self):
fld = self.selectedField()
if fld is not None:
up_enabled = (fld != 0)
down_enabled = (fld != self.fields.model().rowCount()-1)
del_enabled = True
else:
up_enabled, down_enabled, del_enabled = False, False, False
self.btnFieldUp.setEnabled(up_enabled)
self.btnFieldDown.setEnabled(down_enabled)
self.btnDeleteField.setEnabled(del_enabled)
def updatePkeyCombo(self, selRow=None):
""" called when list of columns changes. if 'sel' is None, it keeps current index """
if selRow is None:
selRow = self.cboPrimaryKey.currentIndex()
self.cboPrimaryKey.clear()
m = self.fields.model()
for row in xrange(m.rowCount()):
name = m.data(m.index(row,0)).toString()
self.cboPrimaryKey.addItem(name)
self.cboPrimaryKey.setCurrentIndex(selRow)
def addField(self):
""" add new field to the end of field table """
m = self.fields.model()
newRow = m.rowCount()
m.insertRows(newRow,1)
indexName = m.index(newRow,0,QModelIndex())
indexType = m.index(newRow,1,QModelIndex())
indexNull = m.index(newRow,2,QModelIndex())
m.setData(indexName, QVariant("new_field"))
colType = self.fieldTypes[0]
if newRow == 0:
# adding the first row, use auto-incrementing column type if any
if "serial" in self.fieldTypes: # PostgreSQL
colType = "serial"
m.setData(indexType, QVariant(colType))
m.setData(indexNull, QVariant(False))
# selects the new row
sel = self.fields.selectionModel()
sel.select(indexName, QItemSelectionModel.Rows | QItemSelectionModel.ClearAndSelect)
# starts editing
self.fields.edit(indexName)
self.updatePkeyCombo(0 if newRow == 0 else None)
def selectedField(self):
sel = self.fields.selectedIndexes()
if len(sel) < 1:
return None
return sel[0].row()
def deleteField(self):
""" delete selected field """
row = self.selectedField()
if row is None:
QMessageBox.information(self, "sorry", "no field selected")
else:
self.fields.model().removeRows(row,1)
self.updatePkeyCombo()
def fieldUp(self):
""" move selected field up """
row = self.selectedField()
if row is None:
QMessageBox.information(self, "sorry", "no field selected")
return
if row == 0:
QMessageBox.information(self, "sorry", "field is at top already")
return
# take row and reinsert it
rowdata = self.fields.model().takeRow(row)
self.fields.model().insertRow(row-1, rowdata)
# set selection again
index = self.fields.model().index(row-1, 0, QModelIndex())
self.fields.selectionModel().select(index, QItemSelectionModel.Rows | QItemSelectionModel.ClearAndSelect)
self.updatePkeyCombo()
def fieldDown(self):
""" move selected field down """
row = self.selectedField()
if row is None:
QMessageBox.information(self, "sorry", "no field selected")
return
if row == self.fields.model().rowCount()-1:
QMessageBox.information(self, "sorry", "field is at bottom already")
return
# take row and reinsert it
rowdata = self.fields.model().takeRow(row)
self.fields.model().insertRow(row+1, rowdata)
# set selection again
index = self.fields.model().index(row+1, 0, QModelIndex())
self.fields.selectionModel().select(index, QItemSelectionModel.Rows | QItemSelectionModel.ClearAndSelect)
self.updatePkeyCombo()
def createTable(self):
""" create table with chosen fields, optionally add a geometry column """
if not self.hasSchemas:
schema = None
else:
schema = unicode(self.cboSchema.currentText())
if len(schema) == 0:
QMessageBox.information(self, "sorry", "select schema!")
return
table = unicode(self.editName.text())
if len(table) == 0:
QMessageBox.information(self, "sorry", "enter table name!")
return
m = self.fields.model()
if m.rowCount() == 0:
QMessageBox.information(self, "sorry", "add some fields!")
return
useGeomColumn = self.chkGeomColumn.isChecked()
if useGeomColumn:
geomColumn = unicode(self.editGeomColumn.text())
if len(geomColumn) == 0:
QMessageBox.information(self, "sorry", "set geometry column name")
return
geomType = self.GEOM_TYPES[ self.cboGeomType.currentIndex() ]
geomDim = self.spinGeomDim.value()
try:
geomSrid = int(self.editGeomSrid.text())
except ValueError:
geomSrid = -1
useSpatialIndex = self.chkSpatialIndex.isChecked()
flds = m.getFields()
pk_index = self.cboPrimaryKey.currentIndex()
if pk_index >= 0:
flds[ pk_index ].primaryKey = True
# commit to DB
QApplication.setOverrideCursor(Qt.WaitCursor)
try:
if not useGeomColumn:
self.db.createTable(table, flds, schema)
else:
geom = geomColumn, geomType, geomSrid, geomDim, useSpatialIndex
self.db.createVectorTable(table, flds, geom, schema)
except (ConnectionError, DbError), e:
DlgDbError.showError(e, self)
return
finally:
QApplication.restoreOverrideCursor()
QMessageBox.information(self, "Good", "everything went fine")