/* 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. */ #include #include #include #include "mappingtreemodel.h" #include "smtreeitem.h" #include "smglobals.h" MappingTreeModel::MappingTreeModel(QStringList &headers, QObject *parent) : SmTreeModel(headers, parent), mForbidden("/"), mType(-1) { //init database mDb = QSqlDatabase::database("treedb"); getMappingTypes(); mSParentsQ = "SELECT mapping_parents.imapping_parents_id, mapping_parents.idescription_id, mapping_description.tdescription_name, mapping_description.tscreated, mapping_parents.iparent_id FROM mapping_parents, mapping_description WHERE mapping_parents.iparent_id = :pid AND mapping_description.idescription_type = :type AND mapping_parents.idescription_id = mapping_description.idescription_id ORDER BY mapping_description.tdescription_name"; } QStringList MappingTreeModel::mappingTypeNames() const { QStringList retval; foreach(mappingType t, mMappingTypes){ retval << t.name.toString(); } qSort(retval); return retval; } int MappingTreeModel::mappingTypeIdFromName(const QVariant &name) const{ foreach(const mappingType t, mMappingTypes){ if(t.name == name){ return t.id.toInt(); } } return -1; } QVariant MappingTreeModel::data(const QModelIndex &index, int role) const{ if(!index.isValid()){ return QVariant(); } SmTreeItem *item = itemAt(index); if(role == NameRole){ return item->data(Name); } if(role == MappingIdRole){ return item->data(MappingId); } if(role == DescAddedRole){ return item->data(DescAdded); } if(role == DescIdRole){ return item->data(DescId); } if(role == MappingParentIdRole){ return item->data(MappingParentId); } return SmTreeModel::data(index, role); } QList MappingTreeModel::childList(const QVariant &value, int column) const{ QModelIndex itemIdx = findRecursive(value, column, createIndex(0, column, root())); SmTreeItem *item = static_cast(itemIdx.internalPointer()); if(item){ if(item->childCount()){ return getChildListRecursive(item, column); } } return QList() << value; } QModelIndex MappingTreeModel::indexFromParentPath(const QList &pPath, bool reverse) const{ QList path = pPath; if(reverse){ std::reverse(path.begin(), path.end()); } QModelIndex retval = QModelIndex(); while(!path.isEmpty()){ int curId = path.last(); path.removeLast(); retval = find(curId, MappingId, retval); if(!retval.isValid()){ return QModelIndex(); } } return retval; } bool MappingTreeModel::setData(const QModelIndex &idx, const QVariant &value, int role){ if(!idx.isValid()){ return false; } SmTreeItem *item = itemAt(idx); if(role == Qt::EditRole){ if(idx.column() == Name){ if(value.toString().contains(mForbidden)){ return false; } } updateChild(item, value); } if(role == NameRole){ if(value.toString().contains(mForbidden)){ return false; } item->setData(Name, value); } if(role == MappingIdRole){ item->setData(MappingId, value); } if(role == DescAddedRole){ item->setData(DescAdded, value); } if(role == DescIdRole){ item->setData(DescId, value); } return true; } bool MappingTreeModel::addMappingType(const QString &type){ QSqlQuery addMappingTypeQ(mDb); addMappingTypeQ.prepare("INSERT INTO mappings_type (tmappings_type_name) VALUES(:value)"); addMappingTypeQ.bindValue(":value", type); if(addMappingTypeQ.exec()){ getMappingTypes(); return true; } mLastError = addMappingTypeQ.lastError(); return false; } bool MappingTreeModel::deleteMappingType(int typeId){ QSqlQuery deleteMappingTypeQ(mDb); deleteMappingTypeQ.prepare("DELETE FROM mappings_type WHERE imappings_type_id = :id"); deleteMappingTypeQ.bindValue(":id", typeId); if(deleteMappingTypeQ.exec()){ getMappingTypes(); return true; } mLastError = deleteMappingTypeQ.lastError(); return false; } bool MappingTreeModel::addChild(const QVariant &name, const QModelIndex &parent){ if(!parent.isValid()){ return false; } if(name.toString().contains(mForbidden)){ return false; } //check if we already have a mapping with this name int id = mMappings.value(name.toString(), -1); if(id == -1){ id = addDescription(name.toString(), mType); } QSqlQuery addParentQ(mDb); addParentQ.prepare("INSERT INTO mapping_parents (idescription_id, iparent_id) VALUES(:id, :parentid)"); addParentQ.bindValue(":id", id); addParentQ.bindValue(":parentid", parent.data(MappingIdRole)); if(addParentQ.exec()){ populate(); return true; } mLastError = addParentQ.lastError(); return false; } bool MappingTreeModel::renameChild(const QModelIndex &idx, const QString newName){ if(!idx.isValid()){ return false; } int descId = idx.data(DescIdRole).toInt(); QSqlQuery renameQ(mDb); renameQ.prepare("UPDATE mapping_description SET tdescription_name = :name WHERE idescription_id = :id"); renameQ.bindValue(":id", descId); renameQ.bindValue(":name", newName); if(renameQ.exec()){ populate(); return true; } return false; } bool MappingTreeModel::deleteChild(const QModelIndex &idx){ if(!idx.isValid()){ return false; } SmTreeItem *item = itemAt(idx); if(item->childCount() > 0){ return false; } QSqlQuery deleteChildQ(mDb); deleteChildQ.prepare("DELETE FROM mapping_parents WHERE imapping_parents_id = :id"); deleteChildQ.bindValue(":id", item->data(MappingId)); if(deleteChildQ.exec()){ removeRows(idx.row(), 1, idx.parent()); return true; } mLastError = deleteChildQ.lastError(); return false; } MappingData MappingTreeModel::mappingDataFromItem(SmTreeItem *item) const{ MappingData retval; retval.mappingId = item->data(MappingTreeModel::MappingId).toInt(); retval.descId = item->data(MappingTreeModel::DescId).toInt(); retval.name = item->data(MappingTreeModel::Name).toString(); retval.parents << item->data(MappingTreeModel::MappingId).toInt(); retval.path << item->data(MappingTreeModel::Name).toString(); SmTreeItem *pItem = item->parent(); while(pItem->parent()){ retval.parents << pItem->data(MappingTreeModel::MappingId).toInt(); retval.path << pItem->data(MappingTreeModel::Name).toString(); pItem = pItem->parent(); } std::reverse(retval.parents.begin(), retval.parents.end()); std::reverse(retval.path.begin(), retval.path.end()); return retval; } MappingData MappingTreeModel::mappingDataFromIndex(QModelIndex &idx) const{ if(!idx.isValid()){ return MappingData(); } SmTreeItem *item = static_cast(idx.internalPointer()); return mappingDataFromItem(item); } void MappingTreeModel::populate(){ if(mType == -1){ return; } // get nodes with root as parent QSqlQuery rootQ(mDb); rootQ.prepare(mSParentsQ); rootQ.bindValue(":type", mType); rootQ.bindValue(":pid", -1); if(rootQ.exec()){ SmTreeItem *rootItem = new SmTreeItem(NumFields); rootItem->setData(DescId, -1); rootItem->setData(MappingId, -1); rootItem->setData(MappingParentId, -1); while(rootQ.next()){ QList childData; childData << rootQ.value(2) << rootQ.value(0) << rootQ.value(3) << rootQ.value(1) << rootQ.value(4); SmTreeItem *childItem = new SmTreeItem(childData, rootItem); rootItem->appendChild(childItem); getChildrenRecursive(childItem); } setRoot(rootItem); emit needExpansion(); } } void MappingTreeModel::setType(int type){ mType = type; getMappings(); } void MappingTreeModel::getMappings(){ QSqlQuery descriptionQ(mDb); descriptionQ.prepare("SELECT tdescription_name, idescription_id FROM mapping_description WHERE idescription_type = :type"); descriptionQ.bindValue(":type", mType); if(descriptionQ.exec()){ mMappings.clear(); while(descriptionQ.next()){ mMappings.insert(descriptionQ.value(0).toString(), descriptionQ.value(1).toInt()); } } } int MappingTreeModel::addDescription(const QString &name, int type){ mDb.transaction(); QSqlQuery addDescriptionQ(mDb); addDescriptionQ.prepare("INSERT INTO mapping_description (tdescription_name, idescription_type) VALUES(:name, :type)"); addDescriptionQ.bindValue(":name", name); addDescriptionQ.bindValue(":type", type); if(addDescriptionQ.exec()){ int currval = -1; QSqlQuery curval("SELECT currval('mapping_id__seq')", mDb); while(curval.next()){ currval = curval.value(0).toInt(); } mMappings.insert(name, currval); mDb.commit(); return currval;; } mDb.rollback(); return -1; } void MappingTreeModel::getMappingTypes(){ QSqlQuery typesQ(mDb); typesQ.prepare("SELECT imappings_type_id, tmappings_type_name FROM mappings_type"); bool qRes = typesQ.exec(); if(qRes){ mMappingTypes.clear(); while(typesQ.next()){ mappingType t; t.id = typesQ.value(0); t.name = typesQ.value(1); mMappingTypes << t; } emit mappingTypesChanged(); } } void MappingTreeModel::getChildrenRecursive(SmTreeItem *item){ QSqlQuery cq(mDb); cq.prepare(mSParentsQ); cq.bindValue(":type", mType); cq.bindValue(":pid", item->data(MappingId)); if(cq.exec()){ while(cq.next()){ QList childData; childData << cq.value(2) << cq.value(0) << cq.value(3) << cq.value(1) << cq.value(4); SmTreeItem *child = new SmTreeItem(childData, item); item->appendChild(child); getChildrenRecursive(child); } } } bool MappingTreeModel::updateChild(SmTreeItem *item, const QVariant &value){ QSqlQuery updateMapping(mDb); updateMapping.prepare("UPDATE mapping_description SET tdescription_name = :new WHERE idescription_id = :id"); updateMapping.bindValue(":id", item->data(DescId)); updateMapping.bindValue(":new", value); if(updateMapping.exec()){ populate(); return true; } return false; } QList MappingTreeModel::getChildListRecursive(SmTreeItem *item, int column) const{ QList retval; if(!item){ return retval; } for(int i = 0; i < item->childCount(); ++i){ if(item->child(i)->childCount()){ retval << getChildListRecursive(item->child(i), column); }else{ retval << item->child(i)->data(column); } } return retval; } QString MappingTreeModel::basePath(SmTreeItem *item) const{ QStringList pItems; SmTreeItem *cur = item; while(cur != root()){ pItems << cur->data(Name).toString(); cur = cur->parent(); } if(pItems.isEmpty()){ return QString(); } std::reverse(pItems.begin(), pItems.end()); return pItems.join("/"); } int MappingTreeModel::lowerBound(SmTreeItem *item, const QVariant &value, int column) const { for(int i = 0; i < item->childCount(); ++i){ SmTreeItem *child = item->child(i); if(child->data(column).toString() > value.toString()){ return i; } } return item->childCount(); } MappingTreeResultModel::MappingTreeResultModel(const QStringList &headers, QObject *parent) : SmTreeModel(headers, parent) { mSourceModel = static_cast(SmGlobals::instance()->model("MappingTree")); } Qt::ItemFlags MappingTreeResultModel::flags(const QModelIndex &index) const { Q_UNUSED(index); return (Qt::ItemIsEnabled | Qt::ItemIsSelectable); } QVariant MappingTreeResultModel::data(const QModelIndex &index, int role) const{ if(!index.isValid()){ return QVariant(); } SmTreeItem *item = itemAt(index); if(role == NameRole){ return item->data(Name); } if(role == MappingIdRole){ return item->data(MappingId); } if(role == DescIdRole){ return item->data(DescId); } if(role == ParentIdRole){ return item->data(ParentId); } return SmTreeModel::data(index, role); } bool MappingTreeResultModel::setData(const QModelIndex &index, const QVariant &value, int role){ SmTreeItem *item = itemAt(index); if(role == NameRole){ item->setData(Name, value); return true; } if(role == MappingIdRole){ item->setData(MappingId, value); return true; } if(role == ParentIdRole){ item->setData(ParentId, value); return true; } if(role == DescIdRole){ item->setData(DescId, value); return true; } return SmTreeModel::setData(index, value, role); } void MappingTreeResultModel::addItem(const MappingData &data){ QList pPath = data.parents; if(!mCurrentData.contains(data)){ mCurrentData << data; } QList curPath; std::reverse(pPath.begin(), pPath.end()); MappingTreeModel *mapModel = qobject_cast(SmGlobals::instance()->model("MappingTree")); QModelIndex curIdx = QModelIndex(); int curId = -1; beginResetModel(); while(!pPath.isEmpty()){ curId = pPath.last(); curPath << curId; pPath.removeLast(); QModelIndex lastIdx = curIdx; curIdx = find(curId, MappingId, curIdx); if(!curIdx.isValid()){ QModelIndex sourceIdx = mapModel->indexFromParentPath(curPath, true); if(!sourceIdx.isValid()){ return; //should never happen! } SmTreeItem *pItem; if(!lastIdx.isValid()){ pItem = root(); }else{ pItem = static_cast(lastIdx.internalPointer()); } int row = pItem->childCount(); const QString curName = sourceIdx.data(MappingTreeModel::NameRole).toString(); for(int i = 0; i < pItem->childCount(); ++i){ if(pItem->child(i)->data(Name).toString() > curName){ row = i; } } QVariantList data; data << curName << sourceIdx.data(MappingTreeModel::MappingIdRole) << sourceIdx.data(MappingTreeModel::MappingParentIdRole) << sourceIdx.data(MappingTreeModel::DescIdRole); SmTreeItem *newItem = new SmTreeItem(data, pItem); pItem->insertChild(row, newItem); curIdx = createIndex(row, 0, newItem); } } endResetModel(); } void MappingTreeResultModel::removeItem(const QModelIndex &idx){ if(!idx.isValid()){ return; } SmTreeItem *curItem = static_cast(idx.internalPointer()); MappingData rmData = mSourceModel->mappingDataFromItem(curItem); beginResetModel(); int row = curItem->row(); SmTreeItem *parent = curItem->parent(); parent->removeChild(row); int count = mCurrentData.removeAll(rmData); int toRemove = -1; if(count == 0){ for(int i = 0; i < mCurrentData.count(); ++i){ MappingData cur = mCurrentData.at(i); if(cur.parents.contains(rmData.mappingId)){ toRemove = i; break; } } } if(toRemove > -1 && toRemove < mCurrentData.count()){ mCurrentData.removeAt(toRemove); } endResetModel(); } QList MappingTreeResultModel::getMappings(SmTreeItem *start) const{ QList retval; for(int i = 0; i < start->childCount(); ++i){ SmTreeItem *childItem = start->child(i); if(childItem->childCount()){ retval.append(getMappings(childItem)); }else{ retval << childItem->data(MappingId); } } return retval; } QList MappingTreeResultModel::columnValues(int column) const { return columnValuesRecursive(root(), column); } void MappingTreeResultModel::clearData(){ setRoot(new SmTreeItem(NumFields)); mCurrentData.clear(); } int MappingTreeResultModel::hasChild(SmTreeItem *item, const QVariant &name, int column) const{ for(int i = 0; i < item->childCount(); ++i){ if(item->child(i)->data(column) == name){ return i; } } return -1; } QList MappingTreeResultModel::columnValuesRecursive(SmTreeItem *parent, int column) const { QList retval; if(!parent->childCount()){ return retval; } for(int i = 0; i < parent->childCount(); ++i){ SmTreeItem *child = parent->child(i); QVariant value = child->data(column); if(value.canConvert(QVariant::Int) && (value.toInt() != -1)){ retval << value; } retval << columnValuesRecursive(child, column); } return retval; } MappingData::MappingData() : mappingId(-1), descId(-1) {} bool MappingData::operator ==(const MappingData &other){ bool retval = ( mappingId == other.mappingId && descId == other.descId && name == other.name && parents == other.parents && path == other.path ); return retval; } QDataStream &operator <<(QDataStream &out, const MappingData &v){ out << v.mappingId << v.descId << v.name << v.parents << v.path; return out; } QDataStream &operator >>(QDataStream &in, MappingData &v){ in >> v.mappingId; in >> v.descId; in >> v.name; in >> v.parents; in >> v.path; return in; } bool MappingData::isValid(){ return !(mappingId == -1 && descId == -1); }