dlg_table_properties.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. """
  2. /***************************************************************************
  3. Name : DB Manager
  4. Description : Database manager plugin for QGIS
  5. Date : Oct 13, 2011
  6. copyright : (C) 2011 by Giuseppe Sucameli
  7. email : brush.tyler@gmail.com
  8. The content of this file is based on
  9. - PG_Manager by Martin Dobias (GPLv2 license)
  10. ***************************************************************************/
  11. /***************************************************************************
  12. * *
  13. * This program is free software; you can redistribute it and/or modify *
  14. * it under the terms of the GNU General Public License as published by *
  15. * the Free Software Foundation; either version 2 of the License, or *
  16. * (at your option) any later version. *
  17. * *
  18. ***************************************************************************/
  19. """
  20. from qgis.PyQt.QtCore import Qt, pyqtSignal
  21. from qgis.PyQt.QtWidgets import QDialog, QMessageBox, QApplication
  22. from qgis.utils import OverrideCursor
  23. from .db_plugins.data_model import TableFieldsModel, TableConstraintsModel, TableIndexesModel
  24. from .db_plugins.plugin import BaseError, DbError
  25. from .dlg_db_error import DlgDbError
  26. from .dlg_field_properties import DlgFieldProperties
  27. from .dlg_add_geometry_column import DlgAddGeometryColumn
  28. from .dlg_create_constraint import DlgCreateConstraint
  29. from .dlg_create_index import DlgCreateIndex
  30. from .ui.ui_DlgTableProperties import Ui_DbManagerDlgTableProperties as Ui_Dialog
  31. class DlgTableProperties(QDialog, Ui_Dialog):
  32. aboutToChangeTable = pyqtSignal()
  33. def __init__(self, table, parent=None):
  34. QDialog.__init__(self, parent)
  35. self.table = table
  36. self.setupUi(self)
  37. self.db = self.table.database()
  38. supportCom = self.db.supportsComment()
  39. if not supportCom:
  40. self.tabs.removeTab(3)
  41. m = TableFieldsModel(self)
  42. self.viewFields.setModel(m)
  43. m = TableConstraintsModel(self)
  44. self.viewConstraints.setModel(m)
  45. m = TableIndexesModel(self)
  46. self.viewIndexes.setModel(m)
  47. # Display comment in line edit
  48. m = self.table.comment
  49. self.viewComment.setText(m)
  50. self.btnAddColumn.clicked.connect(self.addColumn)
  51. self.btnAddGeometryColumn.clicked.connect(self.addGeometryColumn)
  52. self.btnEditColumn.clicked.connect(self.editColumn)
  53. self.btnDeleteColumn.clicked.connect(self.deleteColumn)
  54. self.btnAddConstraint.clicked.connect(self.addConstraint)
  55. self.btnDeleteConstraint.clicked.connect(self.deleteConstraint)
  56. self.btnAddIndex.clicked.connect(self.createIndex)
  57. self.btnAddSpatialIndex.clicked.connect(self.createSpatialIndex)
  58. self.btnDeleteIndex.clicked.connect(self.deleteIndex)
  59. # Connect button add Comment to function
  60. self.btnAddComment.clicked.connect(self.createComment)
  61. # Connect button delete Comment to function
  62. self.btnDeleteComment.clicked.connect(self.deleteComment)
  63. self.refresh()
  64. def refresh(self):
  65. self.populateViews()
  66. self.checkSupports()
  67. def checkSupports(self):
  68. allowEditColumns = self.db.connector.hasTableColumnEditingSupport()
  69. self.btnEditColumn.setEnabled(allowEditColumns)
  70. self.btnDeleteColumn.setEnabled(allowEditColumns)
  71. self.btnAddGeometryColumn.setEnabled(self.db.connector.canAddGeometryColumn((self.table.schemaName(), self.table.name)))
  72. self.btnAddSpatialIndex.setEnabled(self.db.connector.canAddSpatialIndex((self.table.schemaName(), self.table.name)))
  73. def populateViews(self):
  74. self.populateFields()
  75. self.populateConstraints()
  76. self.populateIndexes()
  77. def populateFields(self):
  78. """ load field information from database """
  79. m = self.viewFields.model()
  80. m.clear()
  81. for fld in self.table.fields():
  82. m.append(fld)
  83. for col in range(4):
  84. self.viewFields.resizeColumnToContents(col)
  85. def currentColumn(self):
  86. """ returns row index of selected column """
  87. sel = self.viewFields.selectionModel()
  88. indexes = sel.selectedRows()
  89. if len(indexes) == 0:
  90. QMessageBox.information(self, self.tr("DB Manager"), self.tr("No columns were selected."))
  91. return -1
  92. return indexes[0].row()
  93. def addColumn(self):
  94. """ open dialog to set column info and add column to table """
  95. dlg = DlgFieldProperties(self, None, self.table)
  96. if not dlg.exec_():
  97. return
  98. fld = dlg.getField()
  99. with OverrideCursor(Qt.WaitCursor):
  100. self.aboutToChangeTable.emit()
  101. try:
  102. # add column to table
  103. self.table.addField(fld)
  104. self.refresh()
  105. except BaseError as e:
  106. DlgDbError.showError(e, self)
  107. def addGeometryColumn(self):
  108. """ open dialog to add geometry column """
  109. dlg = DlgAddGeometryColumn(self, self.table)
  110. if not dlg.exec_():
  111. return
  112. self.refresh()
  113. def editColumn(self):
  114. """ open dialog to change column info and alter table appropriately """
  115. index = self.currentColumn()
  116. if index == -1:
  117. return
  118. m = self.viewFields.model()
  119. # get column in table
  120. # (there can be missing number if someone deleted a column)
  121. fld = m.getObject(index)
  122. dlg = DlgFieldProperties(self, fld, self.table)
  123. if not dlg.exec_():
  124. return
  125. new_fld = dlg.getField(True)
  126. with OverrideCursor(Qt.WaitCursor):
  127. self.aboutToChangeTable.emit()
  128. try:
  129. fld.update(new_fld.name, new_fld.type2String(), new_fld.notNull, new_fld.default2String(), new_fld.comment)
  130. self.refresh()
  131. except BaseError as e:
  132. DlgDbError.showError(e, self)
  133. def deleteColumn(self):
  134. """Deletes currently selected column """
  135. index = self.currentColumn()
  136. if index == -1:
  137. return
  138. m = self.viewFields.model()
  139. fld = m.getObject(index)
  140. res = QMessageBox.question(self, self.tr("Delete Column"),
  141. self.tr("Are you sure you want to delete column '{0}'?").format(fld.name),
  142. QMessageBox.Yes | QMessageBox.No)
  143. if res != QMessageBox.Yes:
  144. return
  145. with OverrideCursor(Qt.WaitCursor):
  146. self.aboutToChangeTable.emit()
  147. try:
  148. fld.delete()
  149. self.refresh()
  150. except BaseError as e:
  151. DlgDbError.showError(e, self)
  152. def populateConstraints(self):
  153. constraints = self.table.constraints()
  154. if constraints is None:
  155. self.hideConstraints() # not supported
  156. return
  157. m = self.viewConstraints.model()
  158. m.clear()
  159. for constr in constraints:
  160. m.append(constr)
  161. for col in range(3):
  162. self.viewConstraints.resizeColumnToContents(col)
  163. def hideConstraints(self):
  164. index = self.tabs.indexOf(self.tabConstraints)
  165. if index >= 0:
  166. self.tabs.setTabEnabled(index, False)
  167. def addConstraint(self):
  168. """Adds primary key or unique constraint """
  169. dlg = DlgCreateConstraint(self, self.table)
  170. if not dlg.exec_():
  171. return
  172. self.refresh()
  173. def deleteConstraint(self):
  174. """Deletes a constraint """
  175. index = self.currentConstraint()
  176. if index == -1:
  177. return
  178. m = self.viewConstraints.model()
  179. constr = m.getObject(index)
  180. res = QMessageBox.question(self, self.tr("Delete Constraint"),
  181. self.tr("Are you sure you want to delete constraint '{0}'?").format(constr.name),
  182. QMessageBox.Yes | QMessageBox.No)
  183. if res != QMessageBox.Yes:
  184. return
  185. with OverrideCursor(Qt.WaitCursor):
  186. self.aboutToChangeTable.emit()
  187. try:
  188. constr.delete()
  189. self.refresh()
  190. except BaseError as e:
  191. DlgDbError.showError(e, self)
  192. def currentConstraint(self):
  193. """ returns row index of selected index """
  194. sel = self.viewConstraints.selectionModel()
  195. indexes = sel.selectedRows()
  196. if len(indexes) == 0:
  197. QMessageBox.information(self, self.tr("DB Manager"), self.tr("No constraints were selected."))
  198. return -1
  199. return indexes[0].row()
  200. def populateIndexes(self):
  201. indexes = self.table.indexes()
  202. if indexes is None:
  203. self.hideIndexes()
  204. return
  205. m = self.viewIndexes.model()
  206. m.clear()
  207. for idx in indexes:
  208. m.append(idx)
  209. for col in range(2):
  210. self.viewIndexes.resizeColumnToContents(col)
  211. def hideIndexes(self):
  212. index = self.tabs.indexOf(self.tabIndexes)
  213. if index >= 0:
  214. self.tabs.setTabEnabled(index, False)
  215. def createIndex(self):
  216. """Creates an index """
  217. dlg = DlgCreateIndex(self, self.table)
  218. if not dlg.exec_():
  219. return
  220. self.refresh()
  221. def createSpatialIndex(self):
  222. """Creates spatial index for the geometry column """
  223. if self.table.type != self.table.VectorType:
  224. QMessageBox.information(self, self.tr("DB Manager"), self.tr("The selected table has no geometry."))
  225. return
  226. res = QMessageBox.question(self, self.tr("Create Spatial Index"),
  227. self.tr("Create spatial index for field {0}?").format(self.table.geomColumn),
  228. QMessageBox.Yes | QMessageBox.No)
  229. if res != QMessageBox.Yes:
  230. return
  231. # TODO: first check whether the index doesn't exist already
  232. with OverrideCursor(Qt.WaitCursor):
  233. self.aboutToChangeTable.emit()
  234. try:
  235. self.table.createSpatialIndex()
  236. self.refresh()
  237. except BaseError as e:
  238. DlgDbError.showError(e, self)
  239. def currentIndex(self):
  240. """ returns row index of selected index """
  241. sel = self.viewIndexes.selectionModel()
  242. indexes = sel.selectedRows()
  243. if len(indexes) == 0:
  244. QMessageBox.information(self, self.tr("DB Manager"), self.tr("No indices were selected."))
  245. return -1
  246. return indexes[0].row()
  247. def deleteIndex(self):
  248. """Deletes currently selected index """
  249. index = self.currentIndex()
  250. if index == -1:
  251. return
  252. m = self.viewIndexes.model()
  253. idx = m.getObject(index)
  254. res = QMessageBox.question(self, self.tr("Delete Index"),
  255. self.tr("Are you sure you want to delete index '{0}'?").format(idx.name),
  256. QMessageBox.Yes | QMessageBox.No)
  257. if res != QMessageBox.Yes:
  258. return
  259. with OverrideCursor(Qt.WaitCursor):
  260. self.aboutToChangeTable.emit()
  261. try:
  262. idx.delete()
  263. self.refresh()
  264. except BaseError as e:
  265. DlgDbError.showError(e, self)
  266. def createComment(self):
  267. """Adds a comment to the selected table"""
  268. try:
  269. schem = self.table.schema().name
  270. tab = self.table.name
  271. com = self.viewComment.text()
  272. self.db.connector.commentTable(schem, tab, com)
  273. except DbError as e:
  274. DlgDbError.showError(e, self)
  275. return
  276. self.refresh()
  277. # Display successful message
  278. QMessageBox.information(self, self.tr("Add comment"), self.tr("Table successfully commented"))
  279. def deleteComment(self):
  280. """Drops the comment on the selected table"""
  281. try:
  282. schem = self.table.schema().name
  283. tab = self.table.name
  284. self.db.connector.commentTable(schem, tab)
  285. except DbError as e:
  286. DlgDbError.showError(e, self)
  287. return
  288. self.refresh()
  289. # Refresh line edit, put a void comment
  290. self.viewComment.setText('')
  291. # Display successful message
  292. QMessageBox.information(self, self.tr("Delete comment"), self.tr("Comment deleted"))