Change design of DBBrowserDB a bit and support more actions with views

Change the design of DBBrowserDB to store all DB objects in one single
map instead of having one map for table, one for views, one for triggers
etc. This requires some changes in the entire program.

Show more details of views in the DB structure tab, i.e. the names of
the fields included in the view. Allow browsing views in the browse tab
and allow exporting views as CSV.
This commit is contained in:
Martin Kleusberg
2013-01-04 16:38:59 +01:00
parent 9409622e75
commit d12bb62156
5 changed files with 149 additions and 154 deletions

View File

@@ -34,7 +34,7 @@ void createIndexForm::languageChange()
void createIndexForm::tableSelected( const QString & entry )
{
tableMap::Iterator it;
objectMap::Iterator it;
for ( it = mtablemap.begin(); it != mtablemap.end(); ++it ) {
QString tname = it.value().getname() ;
@@ -86,20 +86,20 @@ void createIndexForm::confirmCreate()
}
}
void createIndexForm::populateTable(const tableMap& rmap)
void createIndexForm::populateTable(const QList<DBBrowserObject>& rmap)
{
tableMap::ConstIterator it;
QList<DBBrowserObject>::ConstIterator it;
for ( it = rmap.begin(); it != rmap.end(); ++it ) {
comboTables->addItem( it.value().getname() );
comboTables->addItem( (*it).getname() );
//populate the fields with first table name
if (it==mtablemap.begin()){
/*if (it==mtablemap.begin()){
fieldMap::Iterator fit;
fieldMap fmap = it.value().fldmap;
fieldMap fmap = (*it).value().fldmap;
for ( fit = fmap.begin(); fit != fmap.end(); ++fit ) {
comboFields->addItem( fit.value().getname() );
}
}
}*/
}
}

View File

@@ -241,13 +241,13 @@ public:
createIndexForm(QWidget* parent = 0, Qt::WindowFlags fl = Qt::Window);
~createIndexForm();
tableMap mtablemap;
objectMap mtablemap;
QString createStatement;
public slots:
virtual void tableSelected( const QString & entry );
virtual void confirmCreate();
virtual void populateTable( const tableMap& rmap );
virtual void populateTable(const QList<DBBrowserObject> &rmap );
protected slots:
virtual void languageChange();

View File

@@ -173,56 +173,34 @@ void MainWindow::populateStructure()
return;
}
db.updateSchema();
QStringList tblnames = db.getTableNames();
QStringList tblnames = db.getBrowsableObjectNames();
sqliteHighlighter->setTableNames(tblnames);
tableMap::ConstIterator it;
objectMap::ConstIterator it;
for ( it = db.tbmap.begin(); it != db.tbmap.end(); ++it ) {
//* Table node
for ( it = db.objMap.begin(); it != db.objMap.end(); ++it )
{
// Object node
QTreeWidgetItem *tableItem = new QTreeWidgetItem();
tableItem->setText(0, it.value().getname());
tableItem->setText(1, "table");
tableItem->setText(3, it.value().getsql());
tableItem->setIcon(0, QIcon(":/icons/table"));
tableItem->setIcon(0, QIcon(QString(":/icons/%1").arg((*it).gettype())));
tableItem->setText(0, (*it).getname());
tableItem->setText(1, (*it).gettype());
tableItem->setText(3, (*it).getsql());
ui->dbTreeWidget->addTopLevelItem(tableItem);
//* Field Nodes
fieldMap::ConstIterator fit;
for ( fit = it.value().fldmap.begin(); fit != it.value().fldmap.end(); ++fit ) {
QTreeWidgetItem *fldItem = new QTreeWidgetItem(tableItem);
fldItem->setText( 0, fit.value().getname() );
fldItem->setText( 1, "field" );
fldItem->setText( 2, fit.value().gettype() );
fldItem->setIcon(0, QIcon(":/icons/field"));
// If it is a table add the field Nodes
if((*it).gettype() == "table" || (*it).gettype() == "view")
{
fieldMap::ConstIterator fit;
for ( fit = (*it).fldmap.begin(); fit != (*it).fldmap.end(); ++fit ) {
QTreeWidgetItem *fldItem = new QTreeWidgetItem(tableItem);
fldItem->setText( 0, fit.value().getname() );
fldItem->setText( 1, "field" );
fldItem->setText( 2, fit.value().gettype() );
fldItem->setIcon(0, QIcon(":/icons/field"));
}
// TODO make an options/setting autoexpand
ui->dbTreeWidget->setItemExpanded(tableItem, true);
}
// TODO make an options/setting autoexpand
ui->dbTreeWidget->setItemExpanded(tableItem, true);
}
objectMap::ConstIterator it2;
for ( it2 = db.idxmap.begin(); it2 != db.idxmap.end(); ++it2 ) {
QTreeWidgetItem *item = new QTreeWidgetItem();
item->setText( 0, it2.value().getname() );
item->setText( 1, "index" );
item->setText( 3, it2.value().getsql() );
item->setIcon(0, QIcon(":/icons/index"));
ui->dbTreeWidget->addTopLevelItem(item);
}
for ( it2 = db.viewmap.begin(); it2 != db.viewmap.end(); ++it2 ) {
QTreeWidgetItem *item = new QTreeWidgetItem();
item->setText( 0, it2.value().getname() );
item->setText( 1, "view" );
item->setText( 3, it2.value().getsql() );
item->setIcon(0, QIcon(":/icons/view"));
ui->dbTreeWidget->addTopLevelItem(item);
}
for ( it2 = db.trgmap.begin(); it2 != db.trgmap.end(); ++it2 ) {
QTreeWidgetItem *item = new QTreeWidgetItem();
item->setText( 0, it2.value().getname() );
item->setText( 1, "trigger" );
item->setText( 3, it2.value().getsql() );
item->setIcon(0, QIcon(":/icons/trigger"));
ui->dbTreeWidget->addTopLevelItem(item);
}
}
@@ -245,6 +223,12 @@ void MainWindow::populateTable( const QString & tablename, bool keepColumnWidths
return;
}
// Activate the add and delete record buttons and editing only if a table has been selected
bool is_table = db.getObjectByName(tablename).gettype() == "table";
ui->buttonNewRecord->setEnabled(is_table);
ui->buttonDeleteRecord->setEnabled(is_table);
ui->dataTable->setEditTriggers(is_table ? QAbstractItemView::DoubleClicked | QAbstractItemView::AnyKeyPressed | QAbstractItemView::EditKeyPressed : QAbstractItemView::NoEditTriggers);
if (mustreset){
updateTableView(0, keepColumnWidths);
if (findWin) findWin->resetFields(db.getTableFields(db.curBrowseTableName));
@@ -266,9 +250,12 @@ void MainWindow::resetBrowser()
{
QString sCurrentTable = ui->comboBrowseTable->currentText();
ui->comboBrowseTable->clear();
QStringList tab = db.getTableNames();
if(!tab.isEmpty()) {
ui->comboBrowseTable->addItems(tab);
objectMap tab = db.getBrowsableObjects();
for(objectMap::ConstIterator i=tab.begin();i!=tab.end();++i)
{
ui->comboBrowseTable->addItem(QIcon(QString(":icons/%1").arg(i.value().gettype())), i.value().getname());
//ui->comboBrowseTable->addItems(tab);
}
setRecordsetLabel();
int pos = ui->comboBrowseTable->findText(sCurrentTable);
@@ -577,7 +564,7 @@ void MainWindow::createIndex()
return;
}
createIndexForm dialog(this);
dialog.populateTable(db.tbmap);
dialog.populateTable(db.objMap.values("table"));
if(dialog.exec())
{
if (!db.executeSQL(dialog.createStatement)){
@@ -763,6 +750,10 @@ void MainWindow::doubleClickTable( int row, int col )
return;
}
// Don't allow editing of other objects than tables
if(db.getObjectByName(ui->comboBrowseTable->currentText()).gettype() != "table")
return;
int realRow = row;
editText(realRow , col);
@@ -869,7 +860,7 @@ void MainWindow::importTableFromCSV()
void MainWindow::exportTableToCSV()
{
exportTableCSVForm dialog(this);
dialog.populateOptions(db.getTableNames());
dialog.populateOptions(db.getBrowsableObjectNames());
if(dialog.exec())
{
//load our table
@@ -1081,26 +1072,18 @@ void MainWindow::on_tree_context_menu(const QPoint &qPoint){
}
//** Tree selection changed
void MainWindow::on_tree_selection_changed(){
if (!ui->dbTreeWidget->selectionModel()->hasSelection()){
ui->editDeleteTableAction->setEnabled(false);
ui->editModifyTableAction->setEnabled(false);
ui->editAddFieldActionPopup->setEnabled(false);
ui->editModifyFieldActionPopup->setEnabled(false);
ui->editDeleteFieldActionPopup->setEnabled(false);
return;
}
// Just assume first that something's selected that can not be edited at all
ui->editDeleteTableAction->setEnabled(false);
ui->editModifyTableAction->setEnabled(false);
ui->editAddFieldActionPopup->setEnabled(false);
ui->editModifyFieldActionPopup->setEnabled(false);
ui->editDeleteFieldActionPopup->setEnabled(false);
if(ui->dbTreeWidget->currentItem()->text(1) == "table"){
ui->editDeleteTableAction->setEnabled(true);
ui->editModifyTableAction->setEnabled(true);
ui->editAddFieldActionPopup->setEnabled(true);
ui->editModifyFieldActionPopup->setEnabled(false);
ui->editDeleteFieldActionPopup->setEnabled(false);
}else if(ui->dbTreeWidget->currentItem()->text(1) == "field"){
ui->editAddFieldActionPopup->setEnabled(false);
ui->editDeleteTableAction->setEnabled(false);
ui->editModifyTableAction->setEnabled(false);
}else if(ui->dbTreeWidget->currentItem()->text(1) == "field" && ui->dbTreeWidget->currentItem()->parent()->text(1) == "table"){
ui->editModifyFieldActionPopup->setEnabled(true);
ui->editDeleteFieldActionPopup->setEnabled(true);
}

View File

@@ -8,7 +8,7 @@
#include "SQLLogDock.h"
#include <QApplication>
void DBBrowserTable::addField(int order, const QString& wfield,const QString& wtype)
void DBBrowserObject::addField(int order, const QString& wfield,const QString& wtype)
{
fldmap[order] = DBBrowserField(wfield,wtype);
}
@@ -217,10 +217,7 @@ void DBBrowserDB::close (){
sqlite3_close(_db);
}
_db = 0;
idxmap.clear();
trgmap.clear();
viewmap.clear();
tbmap.clear();
objMap.clear();
idmap.clear();
browseRecs.clear();
browseFields.clear();
@@ -543,26 +540,42 @@ resultMap DBBrowserDB::getFindResults( const QString & wstatement)
}
QStringList DBBrowserDB::getTableNames()
QStringList DBBrowserDB::getBrowsableObjectNames()
{
tableMap::ConstIterator it;
objectMap::ConstIterator it;
QStringList res;
for ( it = tbmap.begin(); it != tbmap.end(); ++it ) {
res.append( it.value().getname() );
for(it=objMap.begin();it!=objMap.end();++it)
{
if(it.key() == "table" || it.key() == "view")
res.append(it.value().getname());
}
return res;
}
objectMap DBBrowserDB::getBrowsableObjects()
{
objectMap::ConstIterator it;
objectMap res;
for(it=objMap.begin();it!=objMap.end();++it)
{
if(it.key() == "table" || it.key() == "view")
res.insert(it.key(), it.value());
}
return res;
}
QStringList DBBrowserDB::getIndexNames()
{
objectMap::Iterator it;
objectMap tmap = idxmap;
QList<DBBrowserObject> tmap = objMap.values("index");
QList<DBBrowserObject>::ConstIterator it;
QStringList res;
for ( it = tmap.begin(); it != tmap.end(); ++it ) {
res.append( it.value().getname() );
res.append( (*it).getname() );
}
return res;
@@ -570,14 +583,16 @@ QStringList DBBrowserDB::getIndexNames()
QStringList DBBrowserDB::getTableFields(const QString & tablename)
{
tableMap::ConstIterator it;
objectMap::ConstIterator it;
QStringList res;
for ( it = tbmap.begin(); it != tbmap.end(); ++it ) {
if (tablename.compare(it.value().getname())==0 ){
for ( it = objMap.begin(); it != objMap.end(); ++it )
{
if((*it).getname() == tablename)
{
fieldMap::ConstIterator fit;
for ( fit = it.value().fldmap.begin(); fit != it.value().fldmap.end(); ++fit ) {
for ( fit = (*it).fldmap.begin(); fit != (*it).fldmap.end(); ++fit ) {
res.append( fit.value().getname() );
}
}
@@ -587,14 +602,16 @@ QStringList DBBrowserDB::getTableFields(const QString & tablename)
QStringList DBBrowserDB::getTableTypes(const QString & tablename)
{
tableMap::ConstIterator it;
objectMap::ConstIterator it;
QStringList res;
for ( it = tbmap.begin(); it != tbmap.end(); ++it ) {
if (tablename.compare(it.value().getname())==0 ){
for ( it = objMap.begin(); it != objMap.end(); ++it )
{
if((*it).getname() == tablename)
{
fieldMap::ConstIterator fit;
for ( fit = it.value().fldmap.begin(); fit != it.value().fldmap.end(); ++fit ) {
for ( fit = (*it).fldmap.begin(); fit != (*it).fldmap.end(); ++fit ) {
res.append( fit.value().gettype() );
}
}
@@ -602,6 +619,19 @@ QStringList DBBrowserDB::getTableTypes(const QString & tablename)
return res;
}
DBBrowserObject DBBrowserDB::getObjectByName(const QString& name)
{
objectMap::ConstIterator it;
QStringList res;
for ( it = objMap.begin(); it != objMap.end(); ++it )
{
if((*it).getname() == name)
return *it;
}
return DBBrowserObject();
}
int DBBrowserDB::getRecordCount()
{
return browseRecs.count();
@@ -629,10 +659,7 @@ void DBBrowserDB::updateSchema( )
const char *tail;
int err=0;
idxmap.clear();
tbmap.clear();
viewmap.clear();
trgmap.clear();
objMap.clear();
lastErrorMessage = QString("no error");
QString statement = "SELECT type, name, sql FROM sqlite_master;";
@@ -647,14 +674,8 @@ void DBBrowserDB::updateSchema( )
val2 = QString((const char *) sqlite3_column_text(vm, 1));
val3 = QString((const char *) sqlite3_column_text(vm, 2));
if(val1 == "table")
tbmap[val2] = DBBrowserTable(GetDecodedQString(val2), GetDecodedQString(val3));
else if(val1 == "index")
idxmap[val2] = DBBrowserObject(GetDecodedQString(val2), GetDecodedQString(val3));
else if(val1 == "view")
viewmap[val2] = DBBrowserObject(GetDecodedQString(val2), GetDecodedQString(val3));
else if(val1 == "trigger")
trgmap[val2] = DBBrowserObject(GetDecodedQString(val2), GetDecodedQString(val3));
if(val1 == "table" || val1 == "index" || val1 == "view" || val1 == "trigger")
objMap.insert(val1, DBBrowserObject(GetDecodedQString(val2), GetDecodedQString(val3), GetDecodedQString(val1)));
else
qDebug("unknown object type %s", val1.toStdString().c_str());
}
@@ -664,35 +685,39 @@ void DBBrowserDB::updateSchema( )
}
qDebug(sqlite3_errmsg(_db));
//now get the field list for each table in tbmap
tableMap::Iterator it;
for ( it = tbmap.begin(); it != tbmap.end(); ++it ) {
statement = "PRAGMA TABLE_INFO(";
statement.append( it.value().getname());
statement.append(");");
logSQL(statement, kLogMsg_App);
err=sqlite3_prepare(_db,statement.toUtf8(),statement.length(),
&vm, &tail);
if (err == SQLITE_OK){
it.value(). fldmap.clear();
int e = 0;
while ( sqlite3_step(vm) == SQLITE_ROW ){
if (sqlite3_column_count(vm)==6) {
QString val1, val2;
int ispk= 0;
val1 = QString((const char *) sqlite3_column_text(vm, 1));
val2 = QString((const char *) sqlite3_column_text(vm, 2));
ispk = sqlite3_column_int(vm, 5);
if (ispk==1){
val2.append(QString(" PRIMARY KEY"));
//now get the field list for each table
objectMap::Iterator it;
for ( it = objMap.begin(); it != objMap.end(); ++it )
{
if((*it).gettype() == "table" || (*it).gettype() == "view")
{
statement = "PRAGMA TABLE_INFO(";
statement.append( (*it).getname());
statement.append(");");
logSQL(statement, kLogMsg_App);
err=sqlite3_prepare(_db,statement.toUtf8(),statement.length(),
&vm, &tail);
if (err == SQLITE_OK){
(*it).fldmap.clear();
int e = 0;
while ( sqlite3_step(vm) == SQLITE_ROW ){
if (sqlite3_column_count(vm)==6) {
QString val1, val2;
int ispk= 0;
val1 = QString((const char *) sqlite3_column_text(vm, 1));
val2 = QString((const char *) sqlite3_column_text(vm, 2));
ispk = sqlite3_column_int(vm, 5);
if (ispk==1){
val2.append(QString(" PRIMARY KEY"));
}
(*it).addField(e,GetDecodedQString(val1),GetDecodedQString(val2));
e++;
}
it.value().addField(e,GetDecodedQString(val1),GetDecodedQString(val2));
e++;
}
sqlite3_finalize(vm);
} else{
lastErrorMessage = QString ("could not get types");
}
sqlite3_finalize(vm);
} else{
lastErrorMessage = QString ("could not get types");
}
}
}

View File

@@ -3,6 +3,7 @@
#include <QStringList>
#include <QMap>
#include <QMultiMap>
#include "sqlite3.h"
class SQLLogDock;
@@ -33,8 +34,7 @@ static QString g_sApplicationNameShort = QString("sqlitebrowser");
static QString g_applicationIconName = QString(":/oldimages/icon16");
typedef QMap<int, class DBBrowserField> fieldMap;
typedef QMap<QString, class DBBrowserTable> tableMap;
typedef QMap<QString, class DBBrowserObject> objectMap;
typedef QMultiMap<QString, class DBBrowserObject> objectMap;
typedef QMap<int, int> rowIdMap;
typedef QList<QStringList> rowList;
@@ -58,32 +58,20 @@ class DBBrowserObject
{
public:
DBBrowserObject() : name( "" ) { }
DBBrowserObject( const QString& wname,const QString& wsql )
: name( wname), sql( wsql )
{ }
QString getname() const { return name; }
QString getsql() const { return sql; }
private:
QString name;
QString sql;
};
class DBBrowserTable
{
public:
DBBrowserTable() : name( "" ) { }
DBBrowserTable( const QString& wname,const QString& wsql )
: name( wname), sql( wsql )
DBBrowserObject( const QString& wname,const QString& wsql, const QString& wtype )
: name( wname), sql( wsql ), type(wtype)
{ }
void addField(int order, const QString& wfield,const QString& wtype);
QString getname() const { return name; }
QString getsql() const { return sql; }
QString gettype() const { return type; }
fieldMap fldmap;
private:
QString name;
QString sql;
QString type;
};
@@ -114,7 +102,9 @@ public:
QStringList getTableFields(const QString & tablename);
QStringList getTableTypes(const QString & tablename);
QStringList getTableNames();
QStringList getBrowsableObjectNames();
objectMap getBrowsableObjects();
DBBrowserObject getObjectByName(const QString& name);
QStringList getIndexNames();
resultMap getFindResults( const QString & wstatement);
int getRecordCount();
@@ -135,10 +125,7 @@ public:
QStringList decodeCSV(const QString & csvfilename, char sep, char quote, int maxrecords, int * numfields);
tableMap tbmap;
objectMap idxmap;
objectMap viewmap;
objectMap trgmap;
objectMap objMap;
rowIdMap idmap;
rowList browseRecs;