Skip to content
This repository has been archived by the owner on Feb 17, 2020. It is now read-only.

Commit

Permalink
show info about selected item in the tree,
Browse files Browse the repository at this point in the history
added icons (from pg_manager),
allow to run queries on databases
  • Loading branch information
brushtyler committed Jun 21, 2011
1 parent e38ee4d commit 0866764
Show file tree
Hide file tree
Showing 43 changed files with 3,835 additions and 215 deletions.
3 changes: 3 additions & 0 deletions .gitignore
@@ -0,0 +1,3 @@
*.pyc
*~

23 changes: 22 additions & 1 deletion db_manager.py
Expand Up @@ -22,7 +22,7 @@

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from .ui.dbmanager_ui import Ui_DBManager
from .ui.DbManager_ui import Ui_DBManager

class DBManager(QMainWindow, Ui_DBManager):

Expand All @@ -37,6 +37,12 @@ def __init__(self, iface, parent=None):
self.restoreGeometry( settings.value("/DB_Manager/geometry").toByteArray() )
self.restoreState( settings.value("/DB_Manager/windowState").toByteArray() )

self.connect(self.treeView, SIGNAL("currentChanged"), self.itemChanged)

self.connect(self.actionRunQuery, SIGNAL("triggered()"), self.runQuery)
self.connect(self.actionExit, SIGNAL("triggered()"), self.close)


def closeEvent(self, e):
# save the window state
settings = QSettings()
Expand All @@ -46,6 +52,21 @@ def closeEvent(self, e):
QMainWindow.closeEvent(self, e)


def itemChanged(self, item):
if item: self.infoTab.showInfo(item)

def runQuery(self):
db = self.treeView.currentDatabase()
if db == None:
QMessageBox.information(self, u"Sorry", u"No database selected or you are not connected.")
return

from dlg_sql_window import DlgSqlWindow
dlg = DlgSqlWindow(self, db)
dlg.exec_()
self.emit( SIGNAL('reloadDatabase'), db)


def registerAction(self, action, menu, callback):
""" register an action to the manager's main menu """
invoke_callback = lambda x: self.__invokeCallback( callback, checked )
Expand Down
2 changes: 1 addition & 1 deletion db_manager_plugin.py
Expand Up @@ -42,7 +42,6 @@ def unload(self):
self.iface.removePluginDatabaseMenu( u"DB Manager", self.action )
if self.dlg != None:
self.dlg.close()
self.dlg = None

def run(self):
if self.dlg == None:
Expand All @@ -52,5 +51,6 @@ def run(self):
self.dlg.show()

def onDestroyed(self, obj):
print ">>>>>> destroyed"
self.dlg = None

85 changes: 52 additions & 33 deletions db_model.py
Expand Up @@ -24,7 +24,9 @@
from PyQt4.QtCore import *
from PyQt4.QtGui import *

from . import db_plugins
from .db_plugins import supportedDbTypes, createDbPlugin
from .db_plugins.plugin import *

try:
from . import resources_rc
except ImportError:
Expand All @@ -33,12 +35,25 @@
class TreeItem(QObject):
def __init__(self, data, parent=None):
QObject.__init__(self, parent)
self.populated = True
self.parentItem = parent
self.itemData = data
self.childItems = []
if parent:
parent.appendChild(self)

def __del__(self):
print "TreeItem.__del__", self, self.data(0)
self.itemData = None

def deleteChildren(self):
for c in self.childItems:
c.parentItem = None
c.deleteChildren()

def populate(self, index):
self.emit( SIGNAL("startToPopulate"), index )

def getItemData(self):
return self.itemData

Expand Down Expand Up @@ -89,45 +104,48 @@ def icon(self):


class ConnectionItem(TreeItem):
def __init__(self, db, parent=None):
TreeItem.__init__(self, db, parent)
def __init__(self, connection, parent=None):
TreeItem.__init__(self, connection, parent)
self.populated = False
self.connect( self, SIGNAL("startToPopulate"), self.__populate)

def data(self, column):
if column == 0:
return self.getItemData().connectionName()
return None
def populate(self):

def __populate(self, index):
if self.populated:
return True

db = self.getItemData()
connection = self.getItemData()
try:
if not db.connect():
if not connection.connect():
return False

except (db_plugins.InvalidDataException, db_plugins.DbError), e:
except (InvalidDataException, ConnectionError), e:
QMessageBox.warning( None, u"Unable to connect", unicode(e) )
return False

schemas = db.connector.schemas()
schemas = connection.db.schemas()
if schemas != None:
for s in schemas:
SchemaItem(s, self)
else:
tables = db.connector.tables()
tables = connection.db.tables()
for t in tables:
TableItem(t, self)

self.populated = True
self.emit( SIGNAL("populated"), index )
return True


class SchemaItem(TreeItem):
def __init__(self, schema, parent):
TreeItem.__init__(self, schema, parent)
self.populated = False
self.connect( self, SIGNAL("startToPopulate"), self.__populate)

# load (shared) icon with first instance of schema item
if not hasattr(SchemaItem, 'schemaIcon'):
Expand All @@ -141,15 +159,15 @@ def data(self, column):
def icon(self):
return self.schemaIcon

def populate(self):
def __populate(self, index):
if self.populated:
return True

schema = self.getItemData()
db = self.parent().getItemData()
for t in db.connector.tables( schema.name ):
for t in self.getItemData().tables():
TableItem(t, self)

self.populated = True
self.emit( SIGNAL("populated"), index )
return True


Expand All @@ -172,9 +190,6 @@ def data(self, column):
elif column == 1:
return self.getItemData().geomType
return None

def childCount(self):
return 0

def icon(self):
geom_type = self.getItemData().geomType
Expand All @@ -193,16 +208,19 @@ def icon(self):


class DBModel(QAbstractItemModel):

def __init__(self, parent=None):
QAbstractItemModel.__init__(self, parent)
self.header = ['Table']
self.header = ['Databases']

self.rootItem = TreeItem(None, None)
for dbtype in db_plugins.supportedDBTypes():
dbpluginclass = db_plugins.create( dbtype )
for dbtype in supportedDbTypes():
dbpluginclass = createDbPlugin( dbtype )
PluginItem( dbpluginclass, self.rootItem )

def __del__(self):
print "DBModel.__del__"
self.rootItem.deleteChildren()
self.rootItem = None

def getItem(self, index):
if not index.isValid():
Expand Down Expand Up @@ -268,20 +286,16 @@ def parent(self, index):

def rowCount(self, parent):
parentItem = parent.internalPointer() if parent.isValid() else self.rootItem
if not parentItem.populated:
self.connect( parentItem, SIGNAL('populated'), self._onDataChanged )
parentItem.populate( parent )
else:
self.disconnect( parentItem, SIGNAL('populated'), self._onDataChanged )
return parentItem.childCount()

def hasChildren(self, parent):
parentItem = parent.internalPointer() if parent.isValid() else self.rootItem
return parentItem.childCount() > 0 or (hasattr(parentItem, 'populated') and parentItem.populated == False)

def canFetchMore(self, parent):
parentItem = parent.internalPointer() if parent.isValid() else self.rootItem
return hasattr(parentItem, 'populated') and parentItem.populated == False

def fetchMore(self, parent):
parentItem = parent.internalPointer() if parent.isValid() else self.rootItem
if hasattr(parentItem, 'populate'):
parentItem.populate()
return parentItem.childCount() > 0 or not parentItem.populated


def setData(self, index, value, role):
Expand All @@ -297,11 +311,16 @@ def setData(self, index, value, role):
# rename schema or table or view
try:
item.getItemData().rename(new_name)
self.emit(SIGNAL('dataChanged(const QModelIndex &, const QModelIndex &)'), index, index)
self._onDataChanged(index)
return True
except db_plugins.DbError, e:
except DbError, e:
DlgDbError.showError(e, None)
return False

return False


def _onDataChanged(self, indexFrom, indexTo=None):
if indexTo == None: indexTo = indexFrom
self.emit( SIGNAL('dataChanged(const QModelIndex &, const QModelIndex &)'), indexFrom, indexTo)

105 changes: 11 additions & 94 deletions db_plugins/__init__.py
Expand Up @@ -23,123 +23,40 @@
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class NotSupportedDBType(Exception):
class NotSupportedDbType(Exception):
def __init__(self, dbtype):
self.msg = u"%s is not supported yet" % dbtype
Exception(self, self.msg)

def __str__(self):
return self.msg.encode('utf-8')

class InvalidDataException(Exception):
def __init__(self, msg):
self.msg = unicode( msg )
Exception(self, self.msg)

def __str__(self):
return self.msg.encode('utf-8')

class DbError(Exception):
def __init__(self, errormsg, query=None):
self.msg = unicode( errormsg )
self.query = unicode( query ) if query else None
Exception(self, self.msg)

def __str__(self):
msg = self.msg
if self.query != None:
msg += u"\nQuery:\n%s" % self.query
return msg.encode('utf-8')


class DBConnector:
def __init__(self, uri):
self.uri = uri

def quoteId(self, identifier):
if hasattr(identifier, '__iter__'):
ids = list()
for i in identifier:
if i == None:
continue
ids.append( self.quoteId(i) )
return u'.'.join( ids )

identifier = unicode(identifier) # make sure it's python unicode string
return u'"%s"' % identifier.replace('"', '""')

def quoteString(self, txt):
""" make the string safe - replace ' with '' """
txt = unicode(txt) # make sure it's python unicode string
return txt.replace("'", "''")



class DBPlugin:
def __init__(self, conn_name):
self.connName = conn_name

def connectionName(self):
return self.connName

def connect(self):
return False

@classmethod
def icon(self):
return None

@classmethod
def typeName(self):
# return the db typename (e.g. 'postgis')
pass

@classmethod
def typeNameString(self):
# return the db typename string (e.g. 'PostGIS')
pass

@classmethod
def connectionSettingsKey(self):
# return the key used to store the connections in settings
pass

@classmethod
def connections(self):
# get the list of connections
conn_list = []
settings = QSettings()
settings.beginGroup( self.connectionSettingsKey() )
for name in settings.childGroups():
conn_list.append( create(self.typeName(), name) )
settings.endGroup()
return conn_list


def init():
def initDbPluginList():
import os
current_dir = os.path.dirname(__file__)
for name in os.listdir(current_dir):
if not os.path.isdir( os.path.join( current_dir, name ) ):
continue
try:
exec( u"from %s import plugin as mod" % name )
except :
exec( u"from .%s import plugin as mod" % name )
except ImportError, e:
continue
plugin_class = mod.classFactory()
SUPPORTED_DBTYPES[ plugin_class.typeName() ] = plugin_class
pluginclass = mod.classFactory()
SUPPORTED_DBTYPES[ pluginclass.typeName() ] = pluginclass
return len(SUPPORTED_DBTYPES) > 0

def supportedDBTypes():
def supportedDbTypes():
return sorted(SUPPORTED_DBTYPES.keys())

def create(dbtype, conn_name=None):
def createDbPlugin(dbtype, conn_name=None):
if not SUPPORTED_DBTYPES.has_key( dbtype ):
raise NotSupportedDBType( dbtype )
raise NotSupportedDbType( dbtype )
dbplugin = SUPPORTED_DBTYPES[ dbtype ]
return dbplugin if conn_name is None else dbplugin(conn_name)


# initialize the plugin list
SUPPORTED_DBTYPES = {}
init()
initDbPluginList()

0 comments on commit 0866764

Please sign in to comment.