|
8 | 8 | #include <QMimeData> |
9 | 9 | #include <QMessageBox> |
10 | 10 | #include <QApplication> |
11 | | -#include <unordered_map> |
12 | | -#include <map> |
13 | 11 |
|
14 | 12 | DbStructureModel::DbStructureModel(DBBrowserDB& db, QObject* parent) |
15 | 13 | : QAbstractItemModel(parent), |
@@ -304,108 +302,78 @@ bool DbStructureModel::dropMimeData(const QMimeData* data, Qt::DropAction action |
304 | 302 | } |
305 | 303 | } |
306 | 304 |
|
307 | | -static long calc_number_of_objects_by_type(const objectMap& objmap, const std::string& type) |
308 | | -{ |
309 | | - auto objects = objmap.equal_range(type); |
310 | | - if(objects.first == objmap.end()) |
311 | | - return 0; |
312 | | - else |
313 | | - return std::distance(objects.first, objects.second); |
314 | | -} |
315 | | - |
316 | 305 | void DbStructureModel::buildTree(QTreeWidgetItem* parent, const std::string& schema) |
317 | 306 | { |
318 | | - // Build a map from object type to tree node to simplify finding the correct tree node later |
319 | | - std::unordered_map<std::string, QTreeWidgetItem*> typeToParentItem; |
320 | | - |
321 | 307 | // Get object map for the given schema |
322 | | - objectMap objmap = m_db.schemata[schema]; |
| 308 | + const objectMap& objmap = m_db.schemata.at(schema); |
323 | 309 |
|
324 | 310 | // Prepare tree |
| 311 | + auto num_tables = std::count_if(objmap.tables.begin(), objmap.tables.end(), [](const auto& t) { return !t.second->isView(); }); |
325 | 312 | QTreeWidgetItem* itemTables = new QTreeWidgetItem(parent); |
326 | 313 | itemTables->setIcon(ColumnName, IconCache::get("table")); |
327 | | - itemTables->setText(ColumnName, tr("Tables (%1)").arg(calc_number_of_objects_by_type(objmap, "table"))); |
328 | | - typeToParentItem.insert({"table", itemTables}); |
| 314 | + itemTables->setText(ColumnName, tr("Tables (%1)").arg(num_tables)); |
329 | 315 |
|
330 | 316 | QTreeWidgetItem* itemIndices = new QTreeWidgetItem(parent); |
331 | 317 | itemIndices->setIcon(ColumnName, IconCache::get("index")); |
332 | | - itemIndices->setText(ColumnName, tr("Indices (%1)").arg(calc_number_of_objects_by_type(objmap, "index"))); |
333 | | - typeToParentItem.insert({"index", itemIndices}); |
| 318 | + itemIndices->setText(ColumnName, tr("Indices (%1)").arg(objmap.indices.size())); |
334 | 319 |
|
| 320 | + auto num_views = std::count_if(objmap.tables.begin(), objmap.tables.end(), [](const auto& t) { return t.second->isView(); }); |
335 | 321 | QTreeWidgetItem* itemViews = new QTreeWidgetItem(parent); |
336 | 322 | itemViews->setIcon(ColumnName, IconCache::get("view")); |
337 | | - itemViews->setText(ColumnName, tr("Views (%1)").arg(calc_number_of_objects_by_type(objmap, "view"))); |
338 | | - typeToParentItem.insert({"view", itemViews}); |
| 323 | + itemViews->setText(ColumnName, tr("Views (%1)").arg(num_views)); |
339 | 324 |
|
340 | 325 | QTreeWidgetItem* itemTriggers = new QTreeWidgetItem(parent); |
341 | 326 | itemTriggers->setIcon(ColumnName, IconCache::get("trigger")); |
342 | | - itemTriggers->setText(ColumnName, tr("Triggers (%1)").arg(calc_number_of_objects_by_type(objmap, "trigger"))); |
343 | | - typeToParentItem.insert({"trigger", itemTriggers}); |
344 | | - |
345 | | - // Get all database objects and sort them by their name. |
346 | | - // This needs to be a multimap because SQLite allows views and triggers with the same name which means that names can appear twice. |
347 | | - std::multimap<std::string, sqlb::ObjectPtr> dbobjs; |
348 | | - for(const auto& it : objmap) |
349 | | - dbobjs.insert({it.second->name(), it.second}); |
| 327 | + itemTriggers->setText(ColumnName, tr("Triggers (%1)").arg(objmap.triggers.size())); |
350 | 328 |
|
351 | | - // Add the database objects to the tree nodes |
352 | | - for(const auto& obj : dbobjs) |
| 329 | + // Add tables and views |
| 330 | + for(const auto& obj : objmap.tables) |
353 | 331 | { |
354 | | - sqlb::ObjectPtr it = obj.second; |
| 332 | + QTreeWidgetItem* item = addNode(schema, obj.second->name(), obj.second->isView() ? "view" : "table", obj.second->originalSql(), obj.second->isView() ? itemViews : itemTables); |
355 | 333 |
|
356 | | - // Object node |
357 | | - QTreeWidgetItem* item = addNode(typeToParentItem.at(sqlb::Object::typeToString(it->type())), it, schema); |
| 334 | + // Add an extra node for the browsable section |
| 335 | + addNode(schema, obj.second->name(), obj.second->isView() ? "view" : "table", obj.second->originalSql(), browsablesRootItem); |
358 | 336 |
|
359 | | - // If it is a table or view add the field nodes, add an extra node for the browsable section |
360 | | - if(it->type() == sqlb::Object::Types::Table || it->type() == sqlb::Object::Types::View) |
361 | | - addNode(browsablesRootItem, it, schema); |
| 337 | + sqlb::StringVector pk_columns; |
| 338 | + if(!obj.second->isView()) |
| 339 | + { |
| 340 | + const auto pk = obj.second->primaryKey(); |
| 341 | + if(pk) |
| 342 | + pk_columns = pk->columnList(); |
| 343 | + } |
362 | 344 |
|
363 | | - // Add field nodes if there are any |
364 | | - sqlb::FieldInfoList fieldList = it->fieldInformation(); |
365 | | - if(!fieldList.empty()) |
| 345 | + for(const auto& field : obj.second->fields) |
366 | 346 | { |
367 | | - sqlb::StringVector pk_columns; |
368 | | - if(it->type() == sqlb::Object::Types::Table) |
369 | | - { |
370 | | - const auto pk = std::dynamic_pointer_cast<sqlb::Table>(it)->primaryKey(); |
371 | | - if(pk) |
372 | | - pk_columns = pk->columnList(); |
373 | | - } |
| 347 | + bool isPK = contains(pk_columns, field.name()); |
| 348 | + bool isFK = obj.second->constraint({field.name()}, sqlb::Constraint::ForeignKeyConstraintType) != nullptr; |
374 | 349 |
|
375 | | - for(const sqlb::FieldInfo& field : fieldList) |
376 | | - { |
377 | | - QTreeWidgetItem *fldItem = new QTreeWidgetItem(item); |
378 | | - bool isFK = false; |
379 | | - if(it->type() == sqlb::Object::Types::Table) |
380 | | - isFK = std::dynamic_pointer_cast<sqlb::Table>(it)->constraint({field.name}, sqlb::Constraint::ForeignKeyConstraintType) != nullptr; |
381 | | - |
382 | | - fldItem->setText(ColumnName, QString::fromStdString(field.name)); |
383 | | - fldItem->setText(ColumnObjectType, "field"); |
384 | | - fldItem->setText(ColumnDataType, QString::fromStdString(field.type)); |
385 | | - fldItem->setText(ColumnSQL, QString::fromStdString(field.sql)); |
386 | | - fldItem->setText(ColumnSchema, QString::fromStdString(schema)); |
387 | | - if(contains(pk_columns, field.name)) |
388 | | - fldItem->setIcon(ColumnName, IconCache::get("field_key")); |
389 | | - else if(isFK) |
390 | | - fldItem->setIcon(ColumnName, IconCache::get("field_fk")); |
391 | | - else |
392 | | - fldItem->setIcon(ColumnName, IconCache::get("field")); |
393 | | - } |
| 350 | + addNode(schema, field.name(), "field", field.toString(" ", " "), item, field.type(), isPK ? "_key" : (isFK ? "_fk" : std::string{})); |
394 | 351 | } |
395 | 352 | } |
| 353 | + |
| 354 | + // Add indices |
| 355 | + for(const auto& obj : objmap.indices) |
| 356 | + { |
| 357 | + QTreeWidgetItem* item = addNode(schema, obj.second->name(), "index", obj.second->originalSql(), itemIndices); |
| 358 | + |
| 359 | + for(const auto& field : obj.second->fields) |
| 360 | + addNode(schema, field.name(), "field", field.toString(" ", " "), item, field.order()); |
| 361 | + } |
| 362 | + |
| 363 | + // Add triggers |
| 364 | + for(const auto& obj : objmap.triggers) |
| 365 | + addNode(schema, obj.second->name(), "trigger", obj.second->originalSql(), itemTriggers); |
396 | 366 | } |
397 | 367 |
|
398 | | -QTreeWidgetItem* DbStructureModel::addNode(QTreeWidgetItem* parent, const sqlb::ObjectPtr& object, const std::string& schema) |
| 368 | +QTreeWidgetItem* DbStructureModel::addNode(const std::string& schema, const std::string& name, const std::string& object_type, const std::string& sql, QTreeWidgetItem* parent_item, const std::string& data_type, const std::string& icon_suffix) |
399 | 369 | { |
400 | | - std::string type = sqlb::Object::typeToString(object->type()); |
401 | | - |
402 | | - QTreeWidgetItem *item = new QTreeWidgetItem(parent); |
403 | | - item->setIcon(ColumnName, IconCache::get(type)); |
404 | | - item->setText(ColumnName, QString::fromStdString(object->name())); |
405 | | - item->setText(ColumnObjectType, QString::fromStdString(type)); |
406 | | - item->setText(ColumnSQL, QString::fromStdString(object->originalSql())); |
| 370 | + QTreeWidgetItem* item = new QTreeWidgetItem(parent_item); |
| 371 | + item->setText(ColumnName, QString::fromStdString(name)); |
| 372 | + item->setText(ColumnObjectType, QString::fromStdString(object_type)); |
| 373 | + item->setText(ColumnDataType, QString::fromStdString(data_type)); |
| 374 | + item->setText(ColumnSQL, QString::fromStdString(sql)); |
407 | 375 | item->setText(ColumnSchema, QString::fromStdString(schema)); |
408 | | - |
| 376 | + item->setIcon(ColumnName, IconCache::get(object_type + icon_suffix)); |
409 | 377 | return item; |
410 | 378 | } |
411 | 379 |
|
|
0 commit comments