diff --git a/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserDbMainWindow.cxx b/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserDbMainWindow.cxx index 93dab3b9fb788b99af14e3e2d0d7d2b6e4f6353b..133cd546ec5356584fdb3ba64d088043f2e60af7 100644 --- a/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserDbMainWindow.cxx +++ b/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserDbMainWindow.cxx @@ -13,54 +13,20 @@ #include <QVariant> #include <QSqlField> #include <vector> +#include <QtGui> +#include <QTextStream> using namespace std; -FaserDbMainWindow::FaserDbMainWindow(QWidget* parent) +FaserDbMainWindow::FaserDbMainWindow(QWidget* parent, FaserGeoEditorApp *parentApp) : QMainWindow(parent) , m_treeView(new QTreeView(this)) , m_standardModel(new QStandardItemModel(this)) { + m_editorApp = parentApp; showMaximized(); -/* setCentralWidget(m_treeView); - - QStandardItem* root = m_standardModel->invisibleRootItem(); - - QSqlTableModel *m_model = new QSqlTableModel(nullptr, m_database); - m_model->setTable("HVS_NODE"); - m_model->select(); - - QList<QStandardItem*> firstRow; - for( int i = 0; i < m_model->record(0).count(); i++) - { - QStandardItem *temp = new QStandardItem(m_model->record(0).value(i).toString()); - firstRow.push_back(temp); - } - - root->appendRow(firstRow); - QList<QStandardItem*> subRow = prepareRow( m_model->record(2).value(0).toString(), m_model->record(2).value(1).toString(), m_model->record(2).value(2).toString(), m_model->record(2).value(3).toString(), m_model->record(2).value(4).toString() ); - firstRow.first()->appendRow(subRow);*/ - -// auto tables = m_database.tables(); -// for (auto it = tables.constBegin(); it != tables.constEnd(); ++it) std::cout << (*it).toLocal8Bit().constData() << std::endl; - -/* QList<QStandardItem*> firstRow = prepareRow("name 1", "leaf 1"); - root->appendRow(firstRow); - QList<QStandardItem*> secondRow = prepareRow("name 2", "leaf 2"); - root->appendRow(secondRow); - QList<QStandardItem*> subRow = prepareRow("subName 1", "subLeaf 1"); - firstRow.first()->appendRow(subRow);*/ - - // m_treeView->setModel(m_standardModel); - // m_treeView->expandAll(); } -// FaserDbMainWindow::~FaserDbMainWindow() -// { -// if (m_standardModel != nullptr) delete m_standardModel; -// if (m_treeView != nullptr) delete m_treeView; -// } - QList<QStandardItem*> FaserDbMainWindow::prepareRow( const QString& name1, const QString& name2, const QString& name3, const QString& name4, const QString& name5) { @@ -84,17 +50,33 @@ void FaserDbMainWindow::setDatabase( QSqlDatabase *db) m_hvsNodeTableModel = new QSqlTableModel(nullptr, m_database); m_hvsNodeTableModel->setTable("HVS_NODE"); m_hvsNodeTableModel->select(); + m_tag2node = new QSqlTableModel(nullptr, m_database); + m_tag2node->setTable("HVS_TAG2NODE"); + m_tag2node->select(); + m_tagcache = new QSqlTableModel(nullptr, m_database); + m_tagcache->setTable("HVS_TAGCACHE"); + m_tagcache->select(); + m_ltag2ltag = new QSqlTableModel(nullptr, m_database); + m_ltag2ltag->setTable("HVS_LTAG2LTAG"); + m_ltag2ltag->select(); return; } void FaserDbMainWindow::initializeWindow() { - //Build second window + //Build second window and third window QDockWidget *secondWid = new QDockWidget(tr("Data"), this); + QDockWidget *thirdWid = new QDockWidget(tr("Root Tags"), this); secondWid->setAllowedAreas(Qt::RightDockWidgetArea); + thirdWid->setAllowedAreas(Qt::LeftDockWidgetArea); m_secondWindow = new FaserDbSecondWindow(this, secondWid); + m_listWidget = new QListWidget(this); +// m_thirdWindow = new FaserDbMainWindow(this, thirdWid); secondWid->setWidget(m_secondWindow); + thirdWid->setWidget(m_listWidget); addDockWidget(Qt::RightDockWidgetArea, secondWid); + addDockWidget(Qt::LeftDockWidgetArea, thirdWid); + m_listWidget->setSelectionMode(QAbstractItemView::SingleSelection); setCentralWidget(m_treeView); @@ -114,10 +96,10 @@ void FaserDbMainWindow::initializeWindow() createStatusBar(); QSqlTableModel *model = m_hvsNodeTableModel; - + for(int i = 0; i < model->rowCount(); i++) { - if(model->record(i).value("PARENT_ID").toInt() == 0) + if(model->record(i).value("NODE_ID").toInt() == 0) { QList<QStandardItem*> topRow; for(int j = 0; j < 2; j++) @@ -130,8 +112,6 @@ void FaserDbMainWindow::initializeWindow() } } - - m_treeView->setModel(m_standardModel); m_treeView->expandAll(); m_treeView->resizeColumnToContents(0); @@ -139,6 +119,11 @@ void FaserDbMainWindow::initializeWindow() m_treeView->setSelectionBehavior(QAbstractItemView::SelectRows); connect(m_treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &FaserDbMainWindow::selectionChanged); + connect(m_listWidget, &QListWidget::currentRowChanged, this, &FaserDbMainWindow::tagRowChanged); + + //Build the list widget + buildListWidget(); + return; } @@ -162,6 +147,13 @@ bool FaserDbMainWindow::isBranch(QString name) //testing custom context menu void FaserDbMainWindow::contextMenu(const QPoint &point) { + /* + Improvements to this sections code: + The end disconnect functions disconnect all + Can remove all other disconnects and create one QAction pointer vector + That we iterate through at the end to delete + */ + //Add branch/leaf functions if selected is a branch if(isBranch(m_currentSelected)) { @@ -174,43 +166,68 @@ void FaserDbMainWindow::contextMenu(const QPoint &point) m_contextMenu->addSeparator(); } - //Add create tag action for hvs_node rows only + //Add create tag and lock action for hvs_node rows only QString current = m_currentSelected; if( !current.endsWith("_DATA") && !current.endsWith("_DATA2TAG")) { - m_createTag = new QAction("Create Tag", m_contextMenu); + if( current == "FASER") + { + m_createTag = new QAction("Create Root Tag", m_contextMenu); + connect(m_createTag, &QAction::triggered, this, &FaserDbMainWindow::createRootTag); + } + else + { + m_createTag = new QAction("Create Tag", m_contextMenu); + connect(m_createTag, &QAction::triggered, this, &FaserDbMainWindow::createTag ); + } + m_lockTag = new QAction("Lock Tag", m_contextMenu); m_contextMenu->addAction(m_createTag); - connect(m_createTag, &QAction::triggered, this, &FaserDbMainWindow::createTag ); + m_contextMenu->addAction(m_lockTag); + //Following is a lambda function, lets us pass lockTag function pointer that has arguments to connect(using default arguments) + connect(m_lockTag, &QAction::triggered, this, [this]() + { + lockTag(); + }); } //If we are looking at root tag, create set root action - if( current == QString("FASER")) + //Obsolete feature, replaced by left root tag list +/* if( current == QString("FASER")) { m_setRoot = new QAction("Set Root Tag", m_contextMenu); m_contextMenu->addAction(m_setRoot); connect(m_setRoot, &QAction::triggered, this, &FaserDbMainWindow::setRoot); - } + }*/ - //Now set current QString to reflect the correspondng data2tag if we are looking at a leaf or data table + //Now make QString to reflect the correspondng data2tag if we are looking at a leaf or data table + QString tagCurrent; if( !isBranch(current) && !current.endsWith("_DATA2TAG")) { + tagCurrent = current; if(current.endsWith("_DATA")) { - current.replace(QString("_DATA"), QString("_DATA2TAG")); + tagCurrent.replace(QString("_DATA"), QString("_DATA2TAG")); } else { - current.append("_DATA2TAG"); + tagCurrent.append("_DATA2TAG"); } } - //First build a submenu action for each tag id and set its internal tag id data - vector<QAction *> actions; - if( current.endsWith("_DATA2TAG") ) + else if (current.endsWith("_DATA2TAG")) { - QSqlTableModel model; - model.setTable(current); + tagCurrent = current; + } + + //Build a submenu action for each tag id and set its internal tag id data + vector<QAction *> tagActions; + vector<QString> tag_ids; + + //Build list leaf nodes + if( !tagCurrent.isNull()) + { + QSqlTableModel model(nullptr, m_database); + model.setTable(tagCurrent); model.select(); - vector<QString> tag_ids; for(int i = 0; i < model.rowCount(); i++) { bool found = false; @@ -227,13 +244,29 @@ void FaserDbMainWindow::contextMenu(const QPoint &point) tag_ids.push_back(model.record(i).value(0).toString()); } } - for(size_t i = 0; i < tag_ids.size(); i++) + } + //Build list for branch nodes -- currently i dont believe we want this functionallity + //Can add back in later, but would need to update setTagFilter's functionality +/* else + { + for(int i = 0; i < m_tagcache.rowCount(); i++) { - QAction * tempAct = new QAction(tag_ids[i], m_subMenu); - actions.push_back(tempAct); - tempAct->setData(tag_ids[i]); - m_subMenu->addAction(tempAct); + if(m_tagcache->record(i).value("CHILDNODE").toString() == current) + { + tag_ids.push_back(m_tagcache->record(i).value("CHILDTAGID").toString()); + } } + }*/ + + for(size_t i = 0; i < tag_ids.size(); i++) + { + QAction * tempAct = new QAction(tag_ids[i], m_subMenu); + tagActions.push_back(tempAct); + tempAct->setData(tag_ids[i]); + m_subMenu->addAction(tempAct); + } + if( !tagCurrent.isNull()) + { connect(m_subMenu, &QMenu::triggered, this, &FaserDbMainWindow::tagAction); } @@ -251,17 +284,18 @@ void FaserDbMainWindow::contextMenu(const QPoint &point) delete m_addBranch; delete m_addLeaf; } - if( current == QString("FASER")) +/* if( current == QString("FASER")) { disconnect(m_contextMenu, &QMenu::triggered, this, &FaserDbMainWindow::setRoot); delete m_setRoot; - } + }*/ if( !current.endsWith("_DATA") && !current.endsWith("_DATA2TAG")) { - disconnect(m_contextMenu, &QMenu::triggered, this, &FaserDbMainWindow::createTag); +// disconnect(m_contextMenu, &QMenu::triggered, this, &FaserDbMainWindow::createTag); delete m_createTag; + delete m_lockTag; } - if( m_currentSelected.endsWith("_DATA2TAG") ) + if( !tagCurrent.isNull() ) { disconnect(m_subMenu, &QMenu::triggered, this, &FaserDbMainWindow::tagAction); @@ -271,10 +305,12 @@ void FaserDbMainWindow::contextMenu(const QPoint &point) } m_subMenu->clear();*/ } - for(size_t i = 0; i < actions.size(); i++) + for(size_t i = 0; i < tagActions.size(); i++) { - delete actions[i]; + delete tagActions[i]; } + disconnect(m_contextMenu, 0,0,0); + disconnect(m_subMenu, 0,0,0); m_subMenu->clear(); } @@ -338,24 +374,117 @@ void FaserDbMainWindow::createActions() fileMenu->addSeparator(); + QAction *saveAct = fileMenu->addAction(tr("&Save as text commands"), this, &FaserDbMainWindow::saveFile); + saveAct->setShortcuts(QKeySequence::Save); + saveAct->setStatusTip(tr("Saves application as a text file containing sql commands to rebuild database")); + QAction *rebuildAct = fileMenu->addAction(tr("&ReBuild"), this, &FaserDbMainWindow::rebuildTree); rebuildAct->setStatusTip(tr("Rebuild tree based off of changes")); QAction *verifyAct = fileMenu->addAction(tr("&Verify Database"), this, &FaserDbMainWindow::verifyDatabase); verifyAct->setStatusTip(tr("Verify database adheres to standards")); + QAction *rootAct = fileMenu->addAction(tr("&Create new root"), this, &FaserDbMainWindow::createRootTag); + rootAct->setStatusTip(tr("Creates a new root tag for a new database version")); + QAction *quitAct = fileMenu->addAction(tr("&Quit"), this, &QWidget::close); quitAct->setShortcuts(QKeySequence::Quit); quitAct->setStatusTip(tr("Quit the application")); - m_viewMenu = menuBar()->addMenu(tr("&View")); } +void FaserDbMainWindow::saveFile() +{ + bool ok; + QString fileName = QInputDialog::getText(this, tr("QInputDialog::getText()"), tr("File name to save to\n(including path if desired)"), QLineEdit::Normal, QString(), &ok); + if( !ok ) + { + cout<<"Failed to get file name to save to\n"; + return; + } + QFile data(fileName); + if (data.open(QFile::WriteOnly)) + { + QTextStream outTxt(&data); + outTxt << "BEGIN TRANSACTION;\n\n"; + QSqlQuery query(m_database); + query.prepare("SELECT * FROM sqlite_master"); //Get names of tables in database + if(query.exec()) + { + while (query.next()) + { + outTxt << "\n"; + //Gets name of table to do new query of it + QString queryText = QString("SELECT * FROM %1").arg(query.record().value(1).toString()); + QSqlQuery subQuery(m_database); + subQuery.prepare(queryText); + bool firstLine=true; + if(subQuery.exec()) + { + outTxt << "DROP TABLE IF EXISTS \""<<query.record().value(1).toString()<<"\";\nCREATE TABLE IF NOT EXISTS \""<<query.record().value(1).toString()<<"\" (\n"; + while( subQuery.next()) + { + const QSqlRecord recrd= subQuery.record(); + //Creates table query + if(firstLine) + { + QSqlQuery typeQuery(m_database); + QString typeString = QString("PRAGMA table_info(%1)").arg(query.record().value(1).toString()); + typeQuery.prepare(typeString); + typeQuery.exec(); + bool prevAdded = false; + while( typeQuery.next()) + { + if(prevAdded) + { + outTxt << ",\n"; + } + prevAdded = true; + QString name = typeQuery.value("name").toString(); + QString type = typeQuery.value("type").toString(); + outTxt << "\t"; + outTxt << "\""<< name <<"\"\t"<< type; //Headers + } + outTxt << "\n);\n\n"; + } + firstLine=false; + outTxt << "INSERT INTO \"" << query.record().value(1).toString()<< "\" VALUES ("; + for(int i=0;i<recrd.count();++i) + { + if( i != 0) + { + outTxt << ", "; + } + if(recrd.value(i).isNull()) + { + outTxt << "NULL"; + } + else + { + if(recrd.value(i).userType() == QMetaType::QString ) + { + outTxt << "'"; + } + outTxt << recrd.value(i).toString(); + if(recrd.value(i).userType() == QMetaType::QString ) + { + outTxt << "'"; + } + } + } + outTxt << ");\n"; + } + } + } + outTxt << "COMMIT;"; + } + data.close(); +} +} + QString FaserDbMainWindow::selectedRowName() { -// int row = m_treeView->currentIndex().row(); -// return m_treeView->model()->data( m_treeView->model()->index(row, 1)).toString(); return m_currentSelected; } @@ -366,11 +495,10 @@ void FaserDbMainWindow::rebuildTree() m_hvsNodeTableModel->select(); QSqlTableModel *model = m_hvsNodeTableModel; -// QSqlTableModel *model = m_secondWindow->tablePointer(); - for(int i = 1; i < model->rowCount(); i++) + for(int i = 0; i < model->rowCount(); i++) { - if(model->record(i).value("PARENT_ID").toInt() == 0) + if(model->record(i).value("NODE_ID").toInt() == 0) { QList<QStandardItem*> topRow; for(int j = 0; j < 2; j++) @@ -383,6 +511,7 @@ void FaserDbMainWindow::rebuildTree() } } + m_treeView->expandAll(); m_treeView->resizeColumnToContents(0); m_treeView->resizeColumnToContents(1); @@ -399,7 +528,8 @@ bool FaserDbMainWindow::verifyDatabase() bool ltag2ltagExists = false; bool tag2nodeExists = false; bool tagcacheExists = false; - vector<QString> masterTables; + vector<string> masterTables; + //Build a list of all tables in the database for(int i = 0; i < masterTable.rowCount(); i++) { QString tableName = masterTable.record(i).value(1).toString(); @@ -409,9 +539,10 @@ bool FaserDbMainWindow::verifyDatabase() tagcacheExists = nodeExists || (tableName.toStdString() == "HVS_tagcache") ? true : false; if(masterTable.record(i).value("type").toString() == "table") { - masterTables.push_back(tableName); + masterTables.push_back(tableName.toStdString()); } } + //Check that main tables exist if( !(ltag2ltagExists && nodeExists && tag2nodeExists && tagcacheExists)) { if(!nodeExists) @@ -509,7 +640,154 @@ bool FaserDbMainWindow::verifyDatabase() } //Now we need to verify that HVS_NODE is built properly + //Ensure a _DATA and _DATA2TAG table for each leaf + //Check no hanging children or extraneous tables + + //First check branch/leaf structure in hvs_node + vector<int> parent_ids; + for(int i = 0; i < hvsNodeTable.rowCount(); i++) + { + if( hvsNodeTable.record(i).value("BRANCH_FLAG").toString() == "1") + { + parent_ids.push_back(hvsNodeTable.record(i).value("NODE_ID").toString().toInt()); + } + } + for(int i = 0; i < hvsNodeTable.rowCount(); i++) + { + QString nodeName = hvsNodeTable.record(i).value("NODE_NAME").toString(); + QString parentId = hvsNodeTable.record(i).value("PARENT_ID").toString(); + QString nodeId = hvsNodeTable.record(i).value("NODE_ID").toString(); + if( nodeId != "0" && std::find(parent_ids.begin(), parent_ids.end(), parentId.toInt()) == parent_ids.end()) + { + string err = "Parent of "; + err += hvsNodeTable.record(i).value("NODE_NAME").toString().toStdString(); + err += "is not a branch"; + m_errors.push_back(err); + } + + //Now do different logic on branch or leaves + //Branches first, ensure there are no _DATA or _DATA2TAG tables for it + if(hvsNodeTable.record(i).value("BRANCH_FLAG").toString() == "1") + { + string check_data = hvsNodeTable.record(i).value("NODE_NAME").toString().toStdString(); + check_data += "_DATA"; + transform(check_data.begin(), check_data.end(), check_data.begin(), ::toupper); + string check_data2tag = hvsNodeTable.record(i).value("NODE_NAME").toString().toStdString(); + check_data2tag += "_DATA2TAG"; + transform(check_data2tag.begin(), check_data2tag.end(), check_data2tag.begin(), ::toupper); + if( std::find(masterTables.begin(), masterTables.end(), check_data) != masterTables.end()) + { + string err = "Found _DATA table for branch node in HVS_NODE : "; + err += check_data; + m_errors.push_back(err); + } + if( std::find(masterTables.begin(), masterTables.end(), check_data2tag) != masterTables.end()) + { + string err = "Found _DATA2TAG table for branch node in HVS_NODE : "; + err += check_data2tag; + m_errors.push_back(err); + } + } + else //Checking leaf + { + string check_data = hvsNodeTable.record(i).value("NODE_NAME").toString().toStdString(); + check_data += "_DATA"; + transform(check_data.begin(), check_data.end(), check_data.begin(), ::toupper); + string check_data2tag = hvsNodeTable.record(i).value("NODE_NAME").toString().toStdString(); + check_data2tag += "_DATA2TAG"; + transform(check_data2tag.begin(), check_data2tag.end(), check_data2tag.begin(), ::toupper); + + vector<int> leafDataIds; + vector<int> leafTagIds; + + auto it = std::find(masterTables.begin(), masterTables.end(), check_data); + if( it != masterTables.end()) + { + //Remove the found table from master list vector if found + masterTables.erase( it); + //Also build list of data id's + QSqlTableModel leaf; + leaf.setTable(QString::fromStdString(check_data)); + leaf.select(); + for(int i = 0; i < leaf.rowCount(); i++) + { + int dataid = leaf.record(i).value(0).toString().toInt(); + if( std::find(leafDataIds.begin(), leafDataIds.end(), dataid) == leafDataIds.end()) + { + leafDataIds.push_back(dataid); + } + else + { + string err = "Repeated data tag in "; + err += check_data; + err += " of "; + err += std::to_string(dataid); + m_errors.push_back(err); + } + } + } + else + { + string err = "Missing _DATA table "; + err += check_data; + m_errors.push_back(err); + } + + it = std::find(masterTables.begin(), masterTables.end(), check_data2tag); + if( it != masterTables.end()) + { + //Erase from list of master tables + masterTables.erase( it); + //Also check that ever data id in _data has a tag + //And that every tag is associated with this table in tag2node + QSqlTableModel leaf; + leaf.setTable(QString::fromStdString(check_data2tag)); + leaf.select(); + + for(int i = 0; i < leaf.rowCount(); i++) + { + int data = leaf.record(i).value(1).toString().toInt(); + int tag = leaf.record(i).value(0).toString().toInt(); + if(std::find(leafDataIds.begin(), leafDataIds.end(), data) == leafDataIds.end()) + { + string err = "No reference to data id "; + err += std::to_string(data); + err += " in "; + err += check_data2tag; + m_errors.push_back(err); + } + if(std::find(leafTagIds.begin(), leafTagIds.end(), tag) != leafTagIds.end()) + { + leafTagIds.push_back(tag); + } + } + + for(size_t i = 0; i < leafTagIds.size(); i++) + { + if( nodeId != findAssociated( &hvsTag2NodeTable, QString("TAG_ID"), QString(leafTagIds[i]), QString("NODE_ID"))) + { + string err = "Tag of "; + err += std::to_string(leafTagIds[i]); + err += "not associated with the node "; + err += nodeName.toStdString(); + m_errors.push_back(err); + } + } + + } + else + { + string err = "Missing _DATA2TAG table "; + err += check_data2tag; + m_errors.push_back(err); + } + + + } + + } + if(m_errors.empty()) @@ -518,6 +796,8 @@ bool FaserDbMainWindow::verifyDatabase() } else { + string err = "Errors were found in database verification - check terminal for log"; + errorMessage(err); printErrors(); return false; } @@ -548,10 +828,42 @@ void FaserDbMainWindow::createStatusBar() void FaserDbMainWindow::buildChildren( QList<QStandardItem*> *PRow, QString parent_id) { QSqlTableModel *model = m_hvsNodeTableModel; + + QSqlTableModel tagcache; + tagcache.setTable("HVS_TAGCACHE"); + tagcache.select(); // QSqlTableModel *model = m_secondWindow->tablePointer(); - for(int i = 1; i < model->rowCount(); i++) + + if(!m_rootDisplayTag.isNull()) + { + for(int j = 0; j < m_tagcache->rowCount(); j++) + { + if(m_tagcache->record(j).value("ROOTTAG").toString() == m_rootDisplayTag + && m_tagcache->record(j).value("CHILDNODE").toString() == PRow->at(1)->data(Qt::DisplayRole).toString()) + { + if( isLocked(m_tagcache->record(j).value("CHILDTAGID").toString())) + { + PRow->at(0)->setBackground(Qt::red); + } + else + { + PRow->at(0)->setBackground(Qt::green); + } + break; + } + } + } + else + { + PRow->at(0)->setBackground(QColor(Qt::white)); + } + + for(int i = 0; i < model->rowCount(); i++) { - if(model->record(i).value("PARENT_ID").toString() == parent_id) + //Add new row if it is a child and part of our current root tag system if we have one + if(model->record(i).value("PARENT_ID").toString() == parent_id && model->record(i).value("NODE_ID").toInt() != 0 + && (m_rootDisplayTag.isNull() || + findAssociatedList( &tagcache, QString("ROOTTAG"), m_rootDisplayTag, QString("CHILDNODE")).contains(model->record(i).value("NODE_NAME").toString()))) { QList<QStandardItem*> *newRow = new QList<QStandardItem*>; for(int j = 0; j < 2; j++) @@ -575,9 +887,35 @@ void FaserDbMainWindow::buildChildren( QList<QStandardItem*> *PRow, QString pare newRow->first()->appendRow(dataRow); newRow->first()->appendRow(data2tagRow); - + if(!m_rootDisplayTag.isNull()) + { + QSqlTableModel tagcache; + tagcache.setTable("HVS_TAGCACHE"); + tagcache.select(); + for(int j = 0; j < tagcache.rowCount(); j++) + { + if(tagcache.record(j).value("ROOTTAG").toString() == m_rootDisplayTag + && tagcache.record(j).value("CHILDNODE").toString() == newRow->at(1)->data(Qt::DisplayRole).toString()) + { + if( isLocked(tagcache.record(j).value("CHILDTAGID").toString())) + { + newRow->at(0)->setBackground(Qt::red); + } + else + { + newRow->at(0)->setBackground(Qt::green); + } + break; + } + } + } + else + { + newRow->at(0)->setBackground(Qt::white); + } } + PRow->first()->appendRow(*newRow); } } @@ -615,9 +953,36 @@ void FaserDbMainWindow::addBranch() return; } + //Can't add branch to a locked table + if( !m_rootDisplayTag.isNull()) + { + for(int i = 0; i < m_tagcache->rowCount(); i++) + { + if(m_tagcache->record(i).value("ROOTTAG").toString() == m_rootDisplayTag + && m_tagcache->record(i).value("CHILDNODE").toString() == selectedRowName()) + { + if(isLocked(m_tagcache->record(i).value("CHILDTAGID").toString())) + { + errorMessage("Cannot add branch to a locked node"); + return; + } + else + { + break; + } + } + } + } + //Get name of table we are creating bool ok; - QString text = QInputDialog::getText(this, tr("QInputDialog::getText()"), tr("New Table Name"), QLineEdit::Normal, QDir::home().dirName(),&ok); + QString text = QInputDialog::getText(this, tr("QInputDialog::getText()"), tr("New Table Name"), QLineEdit::Normal, selectedRowName(),&ok); + if(!findAssociated(m_hvsNodeTableModel, QString("NODE_NAME"), text, QString("NODE_ID")).isNull()) + { + errorMessage("Cannot create new branch with same name as existing branch"); + return; + } + if( !ok) { @@ -642,24 +1007,26 @@ void FaserDbMainWindow::addBranch() int row = m_hvsNodeTableModel->rowCount(); //Need to add new branch into related tag tables with a new tag - QSqlTableModel tag2node; - QSqlTableModel ltag2ltag; - QSqlTableModel tagcache; +/* QSqlTableModel tag2node(nullptr, m_database); + QSqlTableModel ltag2ltag(nullptr, m_database); + QSqlTableModel tagcache(nullptr, m_database); tag2node.setTable("HVS_TAG2NODE"); ltag2ltag.setTable("HVS_LTAG2LTAG"); tagcache.setTable("HVS_TAGCACHE"); tag2node.select(); ltag2ltag.select(); - tagcache.select(); + tagcache.select();*/ QString currentNodeName = selectedRowName(); QString currentNodeId = findAssociated(m_hvsNodeTableModel, QString("NODE_NAME"), currentNodeName, QString("NODE_ID")); + QString parentTagName; QString parentTag; //Need to get unlocked parent tag to make new node under + //Get from user if root tag isn't set if(m_rootDisplayTag.isNull()) { - QStringList parentTags = findAssociatedList(<ag2ltag, QString("CHILD_NODE"), currentNodeId, QString("PARENT_TAG")); + QStringList parentTags = findAssociatedList(m_tag2node, QString("NODE_ID"), currentNodeId, QString("TAG_NAME")); for(int i = 0; i < parentTags.size(); i++) { if( isLocked(parentTags.at(i))) @@ -671,60 +1038,80 @@ void FaserDbMainWindow::addBranch() if(parentTags.isEmpty()) { errorMessage("No unlocked parent tag to choose from"); + return; } else if (parentTags.size() == 1) { - parentTag = parentTags.at(0); + parentTagName = parentTags.at(0); } else { - parentTag = QInputDialog::getItem(this, tr("QInputDialog::getItem()"), tr("Choose parent tag for branch:"), parentTags, 0, false, &ok); + parentTagName = QInputDialog::getItem(this, tr("QInputDialog::getItem()"), tr("Choose parent tag for branch:"), parentTags, 0, false, &ok); if(!ok) { cout<<"Failed to get parent tag for branch\n"; return; } } + parentTag = findAssociated(m_tag2node, QString("TAG_NAME"), parentTagName, QString("TAG_ID")); } - - //CASE WHERE WE HAVE A ROOT TAG SET IE m_rootDisplayTag set + else //Case where we have a root tag, use child tag associated with current + { + for(int i = 0; i < m_tagcache->rowCount(); i++) + { + if(m_tagcache->record(i).value("ROOTTAG").toString() == m_rootDisplayTag + && m_tagcache->record(i).value("CHILDNODE").toString() == currentNodeName) + { + parentTag = m_tagcache->record(i).value("CHILDTAGID").toString(); + break; + } + } + } + if(parentTag.isNull()) + { + errorMessage("Unable to get tag associated with table we are adding a branch to"); + return; + } //Make changes to tag tables //Get new tag number int tagAvailable = 0; QString newTag; - for(int i = 0; i < tag2node.rowCount(); i++) + for(int i = 0; i < m_tag2node->rowCount(); i++) { - tagAvailable = (tag2node.record(i).value("TAG_ID").toString().toInt() > tagAvailable) ? tag2node.record(i).value("TAG_ID").toString().toInt() : tagAvailable; + tagAvailable = (m_tag2node->record(i).value("TAG_ID").toString().toInt() > tagAvailable) ? m_tag2node->record(i).value("TAG_ID").toString().toInt() : tagAvailable; } tagAvailable++; newTag = QString::number(tagAvailable); //Get new tag name QString newTagName; - for(int i = 0; i < tag2node.rowCount(); i++) + for(int i = 0; i < m_tag2node->rowCount(); i++) { - if( tag2node.record(i).value("TAG_ID").toString() == parentTag) + if( m_tag2node->record(i).value("TAG_ID").toString() == parentTag) { - newTagName = tag2node.record(i).value("TAG_NAME").toString(); - newTagName.replace(findAssociated(&tagcache, tr("CHILDTAGID"), parentTag, tr("CHILDNODE")), text); + newTagName = m_tag2node->record(i).value("TAG_NAME").toString(); + newTagName.replace(findAssociated(m_tagcache, tr("CHILDTAGID"), parentTag, tr("CHILDNODE")), text); } } //Add to ltag2ltag - QSqlRecord record = ltag2ltag.record(0); - record.setValue("PARENT_NODE", findAssociated(&tag2node, tr("TAG_ID"), parentTag, tr("NODE_ID"))); + QSqlRecord record = m_ltag2ltag->record(0); + record.setValue("PARENT_NODE", findAssociated(m_tag2node, tr("TAG_ID"), parentTag, tr("NODE_ID"))); record.setValue("PARENT_TAG", parentTag); record.setValue("CHILD_NODE", QString::number(pint)); record.setValue("CHILD_TAG", newTag); - ltag2ltag.insertRecord(-1, record); + m_ltag2ltag->insertRecord(-1, record); record.clear(); - ltag2ltag.database().transaction(); - ltag2ltag.submitAll(); + if(!( m_ltag2ltag->database().transaction() && m_ltag2ltag->submitAll() && m_ltag2ltag->database().commit())) + { + cout<<"Error editing ltag2ltag when inserting branch\n Error: "; + cout<<m_ltag2ltag->database().lastError().text().toStdString()<<endl; + } //Add to tag2node - record = tag2node.record(0); + record = m_tag2node->record(0); record.setValue("NODE_ID", QString::number(pint)); record.setValue("TAG_NAME", newTagName); record.setValue("TAG_ID", newTag); @@ -734,21 +1121,26 @@ void FaserDbMainWindow::addBranch() auto dt = QDateTime::currentMSecsSinceEpoch(); record.setValue("DATE_CREATED", QString::number(dt)); record.setNull("DATE_LOCKED"); - tag2node.insertRecord(-1, record); + m_tag2node->insertRecord(-1, record); record.clear(); - tag2node.database().transaction(); - tag2node.submitAll(); + if(!(m_tag2node->database().transaction() && m_tag2node->submitAll() && m_tag2node->database().commit())) + { + cout<<"Error editing tag2node when inserting branch\n Error: "; + cout<<m_tag2node->database().lastError().text().toStdString()<<endl; + } //Add to tagcache - record = tagcache.record(0); - record.setValue("ROOTTAG", findAssociated( &tagcache, tr("CHILDTAGID"), parentTag, tr("ROOTTAG"))); + record = m_tagcache->record(0); + record.setValue("ROOTTAG", findAssociated( m_tagcache, tr("CHILDTAGID"), parentTag, tr("ROOTTAG"))); record.setValue("CHILDNODE", text); record.setValue("CHILDTAG", newTagName); record.setValue("CHILDTAGID", newTag); - tagcache.insertRecord(-1, record); - tagcache.database().transaction(); - tagcache.submitAll(); - + m_tagcache->insertRecord(-1, record); + if(!m_tagcache->database().transaction() || !m_tagcache->submitAll() || !m_tagcache->database().commit()) + { + cout<<"Error editing tagcache when inserting branch\n Error: "; + cout<<m_tagcache->database().lastError().text().toStdString()<<endl; + } //Also add into hvs_node @@ -758,8 +1150,11 @@ void FaserDbMainWindow::addBranch() m_hvsNodeTableModel->setData(m_hvsNodeTableModel->index(row, 2), m_hvsNodeTableModel->record(modelRow).value("NODE_ID")); m_hvsNodeTableModel->setData(m_hvsNodeTableModel->index(row, 3), 1); - m_hvsNodeTableModel->database().transaction(); - m_hvsNodeTableModel->submitAll(); + if(!(m_hvsNodeTableModel->database().transaction() && m_hvsNodeTableModel->submitAll() && m_hvsNodeTableModel->database().commit())) + { + cout<<"Error editing HVS_NODE when inserting branch\nError: "; + cout<<m_hvsNodeTableModel->database().lastError().text().toStdString()<<endl; + } rebuildTree(); @@ -787,9 +1182,42 @@ void FaserDbMainWindow::addLeaf() return; } + //Can't add branch to a locked table + if( !m_rootDisplayTag.isNull()) + { + for(int i = 0; i < m_tagcache->rowCount(); i++) + { + if(m_tagcache->record(i).value("ROOTTAG").toString() == m_rootDisplayTag + && m_tagcache->record(i).value("CHILDNODE").toString() == selectedRowName()) + { + if(isLocked(m_tagcache->record(i).value("CHILDTAGID").toString())) + { + errorMessage("Cannot add leaf to a locked node"); + return; + } + else + { + break; + } + } + } + } + + //Gets name of new table bool ok; - QString text = QInputDialog::getText(this, tr("QInputDialog::getText()"), tr("New Table Name"), QLineEdit::Normal, QDir::home().dirName(),&ok); + QString text = QInputDialog::getText(this, tr("QInputDialog::getText()"), tr("New Table Name"), QLineEdit::Normal, selectedRowName(),&ok); + if(!ok) + { + cout<<"Failed to get name for new leaf\n"; + return; + } + if(!findAssociated(m_hvsNodeTableModel, QString("NODE_NAME"), text, QString("NODE_ID")).isNull()) + { + errorMessage("Leaf name input that is already in use"); + return; + } + //Get a new node_id for our leaf int pint = m_hvsNodeTableModel->record(modelRow).value("NODE_ID").toInt(); pint = pint * 10; int i = 0; @@ -804,92 +1232,240 @@ void FaserDbMainWindow::addLeaf() } int row = m_hvsNodeTableModel->rowCount(); + + //This inserts new row inside of of HVS_NODE + m_hvsNodeTableModel->insertRow( row); + m_hvsNodeTableModel->setData(m_hvsNodeTableModel->index(row, 0), pint); + m_hvsNodeTableModel->setData(m_hvsNodeTableModel->index(row, 1), text); + m_hvsNodeTableModel->setData(m_hvsNodeTableModel->index(row, 2), m_hvsNodeTableModel->record(modelRow).value("NODE_ID")); + m_hvsNodeTableModel->setData(m_hvsNodeTableModel->index(row, 3), 0); + if(!(m_hvsNodeTableModel->database().transaction() && m_hvsNodeTableModel->submitAll() && m_hvsNodeTableModel->database().commit())) + { + cout<<"Error editing HVS_NODE when inserting leaf\nError: "; + cout<<m_hvsNodeTableModel->database().lastError().text().toStdString()<<endl; + } - if( ok && !text.isEmpty()) - { - //This inserts new row inside of of HVS_NODE - m_hvsNodeTableModel->insertRow( row); - m_hvsNodeTableModel->setData(m_hvsNodeTableModel->index(row, 0), pint); - m_hvsNodeTableModel->setData(m_hvsNodeTableModel->index(row, 1), text); - m_hvsNodeTableModel->setData(m_hvsNodeTableModel->index(row, 2), m_hvsNodeTableModel->record(modelRow).value("NODE_ID")); - m_hvsNodeTableModel->setData(m_hvsNodeTableModel->index(row, 3), 0); - - //This will create the _DATA and _DATA2TAG tables in the database - QString dataname = text; - QString tagname = text; - dataname.append("_DATA"); - tagname.append("_DATA2TAG"); - - QString dataquery; - QString data2tagquery; - QString dataidstring = text; - dataidstring.append("_DATA_ID"); - QString tagidstring = text; - tagidstring.append("_TAG_ID"); - dataquery = QString("CREATE TABLE IF NOT EXISTS %1 (%2 SLONGLONG UNIQUE)").arg(dataname).arg(dataidstring); - data2tagquery = QString("CREATE TABLE IF NOT EXISTS %1(%2 SLONGLONG, %3 SLONGLONG)").arg(tagname).arg(tagidstring).arg(dataidstring); - - QSqlQuery querydata(m_database); - querydata.prepare(dataquery); - QSqlQuery querydata2tag(m_database); - querydata2tag.prepare(data2tagquery); + //Also edit tag tables + QString parentTagName; + QString parentTag; + QString currentNodeName = selectedRowName(); + QString currentNodeId = findAssociated(m_hvsNodeTableModel, QString("NODE_NAME"), currentNodeName, QString("NODE_ID")); - if( !querydata.exec()) + //Need to get unlocked parent tag to make new node under + //Get from user if root tag isn't set + if(m_rootDisplayTag.isNull()) + { + QStringList parentTags = findAssociatedList(m_tag2node, QString("NODE_ID"), currentNodeId, QString("TAG_NAME")); + for(int i = 0; i < parentTags.size(); i++) + { + if( isLocked(parentTags.at(i))) + { + parentTags.removeAt(i); + i--; + } + } + if(parentTags.isEmpty()) { - qDebug() << querydata.lastError().text(); //error in building table + errorMessage("No unlocked parent tag to choose from"); + return; } - if( !querydata2tag.exec()) + else if (parentTags.size() == 1) { - qDebug() << querydata2tag.lastError().text(); //error in building table + parentTagName = parentTags.at(0); } - - m_hvsNodeTableModel->database().transaction(); - m_hvsNodeTableModel->submitAll(); - - rebuildTree(); - } - else - { - cout<<"Invalid table name\n"; + else + { + parentTagName = QInputDialog::getItem(this, tr("QInputDialog::getItem()"), tr("Choose parent tag for branch:"), parentTags, 0, false, &ok); + if(!ok) + { + cout<<"Failed to get parent tag for leaf\n"; + return; + } + } + parentTag = findAssociated(m_tag2node, QString("TAG_NAME"), parentTagName, QString("TAG_ID")); + } - -} - -//Current filler function, is dynamic action function that utilized the data put insode the action -void FaserDbMainWindow::tagAction(QAction *action) -{ - //Get the saved data in the action, which is the tag we are filtering for - QString input = action->data().toString(); - - m_secondWindow->setTagFilter(input); - -} - -//This function is used to check if a tagId is locked according to HVS_TAG2NODE -bool FaserDbMainWindow::isLocked(QString tagId) -{ - QSqlTableModel tag2node; - tag2node.setTable("HVS_TAG2NODE"); - tag2node.select(); - - int i = 0; - for(; i < tag2node.rowCount(); i++) + else //Case where we have a root tag, use chold tag associated with current { - if( tag2node.record(i).value("TAG_ID").toString() == tagId) + for(int i = 0; i < m_tagcache->rowCount(); i++) { - break; + if(m_tagcache->record(i).value("ROOTTAG").toString() == m_rootDisplayTag + && m_tagcache->record(i).value("CHILDNODE").toString() == currentNodeName) + { + parentTag = m_tagcache->record(i).value("CHILDTAGID").toString(); + break; + } } } - if(tag2node.record(i).value("TAG_ID").toString() == tagId) + if(parentTag.isNull()) { - return tag2node.record(i).value("LOCKED").toBool(); + errorMessage("Unable to get tag associated with table we are adding a leaf to"); + return; } - return false; + + //Make changes to tag tables + //Get new tag number + int tagAvailable = 0; + QString newTag; + for(int i = 0; i < m_tag2node->rowCount(); i++) + { + tagAvailable = (m_tag2node->record(i).value("TAG_ID").toString().toInt() > tagAvailable) ? m_tag2node->record(i).value("TAG_ID").toString().toInt() : tagAvailable; + } + tagAvailable++; + newTag = QString::number(tagAvailable); + + //Get new tag name + QString newTagName; + for(int i = 0; i < m_tag2node->rowCount(); i++) + { + if( m_tag2node->record(i).value("TAG_ID").toString() == parentTag) + { + newTagName = m_tag2node->record(i).value("TAG_NAME").toString(); + newTagName.replace(findAssociated(m_tagcache, tr("CHILDTAGID"), parentTag, tr("CHILDNODE")), text); + } + } + + //Add to ltag2ltag + QSqlRecord record = m_ltag2ltag->record(0); + record.setValue("PARENT_NODE", findAssociated(m_tag2node, tr("TAG_ID"), parentTag, tr("NODE_ID"))); + record.setValue("PARENT_TAG", parentTag); + record.setValue("CHILD_NODE", QString::number(pint)); + record.setValue("CHILD_TAG", newTag); + m_ltag2ltag->insertRecord(-1, record); + record.clear(); + if(!( m_ltag2ltag->database().transaction() && m_ltag2ltag->submitAll() && m_ltag2ltag->database().commit())) + { + cout<<"Error editing ltag2ltag when inserting leaf\n Error: "; + cout<<m_ltag2ltag->database().lastError().text().toStdString()<<endl; + } + + //Add to tag2node + record = m_tag2node->record(0); + record.setValue("NODE_ID", QString::number(pint)); + record.setValue("TAG_NAME", newTagName); + record.setValue("TAG_ID", newTag); + record.setNull("TAG_COMMENT"); + record.setValue("LOCKED", tr("0")); + record.setValue("REPLICATED", tr("0")); + auto dt = QDateTime::currentMSecsSinceEpoch(); + record.setValue("DATE_CREATED", QString::number(dt)); + record.setNull("DATE_LOCKED"); + m_tag2node->insertRecord(-1, record); + record.clear(); + if(!(m_tag2node->database().transaction() && m_tag2node->submitAll() && m_tag2node->database().commit())) + { + cout<<"Error editing tag2node when inserting leaf\n Error: "; + cout<<m_tag2node->database().lastError().text().toStdString()<<endl; + } + + //Add to tagcache + record = m_tagcache->record(0); + record.setValue("ROOTTAG", findAssociated( m_tagcache, tr("CHILDTAGID"), parentTag, tr("ROOTTAG"))); + record.setValue("CHILDNODE", text); + record.setValue("CHILDTAG", newTagName); + record.setValue("CHILDTAGID", newTag); + m_tagcache->insertRecord(-1, record); + if(!m_tagcache->database().transaction() || !m_tagcache->submitAll() || !m_tagcache->database().commit()) + { + cout<<"Error editing tagcache when inserting leaf\n Error: "; + cout<<m_tagcache->database().lastError().text().toStdString()<<endl; + } + + //This will create the _DATA and _DATA2TAG tables in the database + QString dataname = text.toUpper(); + QString tagname = text.toUpper(); + dataname.append("_DATA"); + tagname.append("_DATA2TAG"); + + QString dataquery; + QString data2tagquery; + QString dataidstring = text; + dataidstring.append("_DATA_ID"); + QString tagidstring = text; + tagidstring.append("_TAG_ID"); + dataquery = QString("CREATE TABLE IF NOT EXISTS %1 (%2 SLONGLONG UNIQUE)").arg(dataname).arg(dataidstring); + data2tagquery = QString("CREATE TABLE IF NOT EXISTS %1(%2 SLONGLONG, %3 SLONGLONG)").arg(tagname).arg(tagidstring).arg(dataidstring); + QSqlQuery querydata(m_database); + if(!querydata.prepare(dataquery)) + { + cout<<"prepare fail\n"; + } + QSqlQuery querydata2tag(m_database); + if(!querydata2tag.prepare(data2tagquery)) + { + cout<<"prepare fail\n"; + } + if( !querydata.exec()) + { + cout<<querydata.lastError().text().toStdString(); //error in building table + } + if( !querydata2tag.exec()) + { + cout<<querydata2tag.lastError().text().toStdString(); //error in building table + } + + + //Create a first row for each _DATA and _DATA2TAG + QSqlQuery dataRow; + QSqlQuery data2TagRow; + dataquery = QString("INSERT INTO %1 VALUES (?)").arg(dataname); + data2tagquery = QString("INSERT INTO %1 VALUES(?, ?)").arg(tagname); + dataRow.prepare(dataquery); + data2TagRow.prepare(data2tagquery); + dataRow.bindValue(0, 1); + data2TagRow.bindValue(0, tagAvailable); + data2TagRow.bindValue(1, 1); + if(!dataRow.exec()) + { + cout<<dataRow.lastError().text().toStdString(); + } + if(!data2TagRow.exec()) + { + cout<<data2TagRow.lastError().text().toStdString(); + } + + + + rebuildTree(); + +} + +//Current filler function, is dynamic action function that utilized the data put insode the action +void FaserDbMainWindow::tagAction(QAction *action) +{ + //Get the saved data in the action, which is the tag we are filtering for + QString input = action->data().toString(); + + m_secondWindow->setTagFilter(input); + +} + +//This function is used to check if a tagId is locked according to HVS_TAG2NODE +bool FaserDbMainWindow::isLocked(QString tagId) +{ + QSqlTableModel tag2node(nullptr, m_database); + tag2node.setTable("HVS_TAG2NODE"); + tag2node.select(); + + int i = 0; + for(; i < tag2node.rowCount(); i++) + { + if( tag2node.record(i).value("TAG_ID").toString() == tagId) + { + break; + } + } + if(tag2node.record(i).value("TAG_ID").toString() == tagId) + { + return tag2node.record(i).value("LOCKED").toBool(); + } + return false; } +/* Old function to change roots from right click menu on tree, replaced by list on left void FaserDbMainWindow::setRoot() { - QSqlTableModel tag2node; + QSqlTableModel tag2node(nullptr, m_database); tag2node.setTable("HVS_TAG2NODE"); tag2node.select(); @@ -902,16 +1478,17 @@ void FaserDbMainWindow::setRoot() cout<<"Failed to get root tag to set\n"; return; } - if( rootTag == QString("Clear root tag")) + if( rootTag == rootTags.last()) { QString nullstr; m_rootDisplayTag = nullstr; + rebuildTree(); return; } m_rootDisplayTag = rootTag; rebuildTree(); -} +}*/ //Function is used to find associated values, ie given a child tag id find parent tag id QStringList FaserDbMainWindow::findAssociatedList(QSqlTableModel *table, QString known, QString kvalue, QString search) @@ -942,138 +1519,213 @@ QString FaserDbMainWindow::findAssociated(QSqlTableModel *table, QString known, return found; } -QString FaserDbMainWindow::createTag() +QString FaserDbMainWindow::createRootTag() { - //This function only works if used on root, or on a node whose parent has a unlocked tag - //Get tag we are creating under - QString nodeGettingTagName = selectedRowName(); - QString nodeGettingTagId = findAssociated( m_hvsNodeTableModel, QString("NODE_NAME"), nodeGettingTagName, QString("NODE_ID")); + //This function is only called in case where we right clicked or selected from menu + //Creates a new root tag, similar to making a new version of the database + + QString nodeGettingTagName = QString("FASER"); + QString nodeGettingTagId = QString("0"); QString newTag; QString nullTag; - QSqlTableModel ltag2ltag; - ltag2ltag.setTable("HVS_LTAG2LTAG"); - ltag2ltag.select(); - QSqlTableModel tag2node; - tag2node.setTable("HVS_TAG2NODe"); - tag2node.select(); - QSqlTableModel tagcache; - tagcache.setTable("HVS_TAGCACHE"); - tagcache.select(); bool ok = false; int tagAvailable = 0; - for(int i = 0; i < tag2node.rowCount(); i++) + for(int i = 0; i < m_tag2node->rowCount(); i++) { - tagAvailable = (tag2node.record(i).value("TAG_ID").toString().toInt() > tagAvailable) ? tag2node.record(i).value("TAG_ID").toString().toInt() : tagAvailable; + tagAvailable = (m_tag2node->record(i).value("TAG_ID").toString().toInt() > tagAvailable) ? m_tag2node->record(i).value("TAG_ID").toString().toInt() : tagAvailable; } tagAvailable++; newTag = QString::number(tagAvailable); - //Case where we are making a root tag - if(nodeGettingTagName == "FASER") + QString rootTag = QInputDialog::getItem(this, tr("QInputDialog::getText()"), tr("New Root Tag name:"), + findAssociatedList( m_tag2node, QString("NODE_ID"), nodeGettingTagId, QString("TAG_NAME")), 0, true, &ok); + if( !ok) { + cout<<"Error in name given/closed window\n"; + return nullTag; + } - QString rootTag = QInputDialog::getItem(this, tr("QInputDialog::getText()"), tr("New Root Tag name:"), - findAssociatedList( &tag2node, QString("NODE_ID"), nodeGettingTagId, QString("TAG_NAME")), 0, true, &ok); - if( !ok) + //Prevent repeated root name + for(int i = 0; i < m_tagcache->rowCount(); i++) + { + if(m_tagcache->record(i).value(0).toString() == rootTag) { - cout<<"Error in name given/closed window\n"; + errorMessage("Root tag name input is already taken"); return nullTag; } + } - //Prevent repeated root name - for(int i = 0; i < tagcache.rowCount(); i++) + //Get tag we will make this new one as a replica of + QStringList replicateList; + for(int i = 0; i < m_tagcache->rowCount(); i++) + { + if( !replicateList.contains(m_tagcache->record(i).value("ROOTTAG").toString())) { - if(tagcache.record(i).value(0).toString() == rootTag) - { - QMessageBox messageBox; - messageBox.critical(0, "Error", "Root tag name input is already taken"); - messageBox.setFixedSize(500,200); - messageBox.exec(); - } + replicateList.push_back(m_tagcache->record(i).value("ROOTTAG").toString()); } + } + QString replicateTagName = QInputDialog::getItem(this, tr("QInputDialog::getItem()"), tr("Root tag to initially copy:"), replicateList, 0, false, &ok); + if( !ok) + { + cout<<"Failed to get tag to replicate to/closed window\n"; + return nullTag; + } - //Get tag we will make this new one as a replica of - QStringList replicateList; - for(int i = 0; i < tagcache.rowCount(); i++) - { - if( !replicateList.contains(tagcache.record(i).value("ROOTTAG").toString())) - { - replicateList.push_back(tagcache.record(i).value("ROOTTAG").toString()); - } - } - QString replicateTag = QInputDialog::getItem(this, tr("QInputDialog::getItem()"), tr("Root tag to initially copy:"), replicateList, 0, false, &ok); - if( !ok) - { - cout<<"Failed to get tag to replicate to/closed window\n"; - return nullTag; - } + QString replicateTagId = findAssociated(m_tag2node, QString("TAG_NAME"), replicateTagName, QString("TAG_ID")); - //Get list of children who will be under our new tag so we put proper children under our new tag - QStringList childTags = findAssociatedList( &tagcache, tr("ROOTTAG"), replicateTag, tr("CHILDTAG")); + //Get list of children who will be under our new tag so we put proper children under our new tag + QStringList childTags = findAssociatedList( m_tagcache, tr("ROOTTAG"), replicateTagName, tr("CHILDTAG")); - //Valid root tag name - //Make appropriate row inserts in each table - //Get highest tag value then increment - //Edit ltag2ltag - for(int i = 0; i < ltag2ltag.rowCount(); i++) + //Valid root tag name + //Make appropriate row inserts in each table + //Get highest tag value then increment + //Edit ltag2ltag + for(int i = 0; i < m_ltag2ltag->rowCount(); i++) + { + if( m_ltag2ltag->record(i).value("PARENT_NODE").toString() == "0" + && m_ltag2ltag->record(i).value("PARENT_TAG").toString() == replicateTagId) { - if( ltag2ltag.record(i).value("PARENT_NODE").toString() == "0" - && ltag2ltag.record(i).value("PARENT_TAG").toString() != newTag - && childTags.contains(ltag2ltag.record(i).value("CHILD_TAG").toString())) - { - QSqlRecord record = ltag2ltag.record(i); - record.setValue("PARENT_TAG", newTag); + QSqlRecord record = m_ltag2ltag->record(i); + record.setValue("PARENT_TAG", newTag); - ltag2ltag.insertRecord(-1, record); - } + m_ltag2ltag->insertRecord(-1, record); } - ltag2ltag.submitAll(); + } + submitChanges(m_ltag2ltag); +/* if(!(m_ltag2ltag->database().transaction() && m_ltag2ltag->submitAll() && m_ltag2ltag->database().commit())) + { + cout<<"Error editing ltag2ltag when inserting new root tag\n Error: "; + cout<<m_ltag2ltag->database().lastError().text().toStdString()<<endl; + }*/ - //Edit tag2node - for(int i = 0; i < tag2node.rowCount(); i++) + //Edit tag2node + if(!( m_tag2node->database().transaction())) + { + cout<<"Error starting transaction : "<<m_tag2node->database().lastError().text().toStdString()<<endl; + } + for(int i = 0; i < m_tag2node->rowCount(); i++) + { + if( m_tag2node->record(i).value("NODE_ID").toString() == "0") { - if( tag2node.record(i).value("TAG_NAME").toString() == replicateTag) - { - QSqlRecord record = tag2node.record(i); - record.setValue("TAG_NAME", rootTag); - record.setValue("TAG_ID", newTag); - record.setNull("TAG_COMMENT"); - record.setValue("LOCKED", QString("0")); - record.setValue("REPLICATED", QString("0")); - auto dt = QDateTime::currentMSecsSinceEpoch(); - record.setValue("DATE_CREATED", QString::number(dt)); - record.setNull("DATE_LOCKED"); - - tag2node.insertRecord(-1, record); +/* QSqlRecord record = m_tag2node->record(i); + record.setValue("TAG_NAME", rootTag); + record.setValue("TAG_ID", newTag); + record.setNull("TAG_COMMENT"); + record.setValue("LOCKED", QString("0")); + record.setValue("REPLICATED", QString("0")); + auto dt = QDateTime::currentMSecsSinceEpoch(); + record.setValue("DATE_CREATED", QString::number(dt)); + record.setNull("DATE_LOCKED"); + if(!m_tag2node->insertRecord(-1, record)) + { + cout<<"failed to insert tag2node record\n"; + cout<<m_tag2node->lastError().text().toStdString()<<endl; } + int row = m_tag2node->rowCount(); + if(!m_tag2node->insertRow(row)) + { + cout<<"failed to insert row\n"; + } + m_tag2node->record(row).setValue("TAG_NAME", rootTag); + m_tag2node->record(row).setValue("TAG_ID", newTag); + m_tag2node->record(row).setNull("TAG_COMMENT"); + m_tag2node->record(row).setValue("LOCKED", QString("0")); + m_tag2node->record(row).setValue("REPLICATED", QString("0")); + auto dt = QDateTime::currentMSecsSinceEpoch(); + m_tag2node->record(row).setValue("DATE_CREATED", QString::number(dt)); + m_tag2node->record(row).setNull("DATE_LOCKED");*/ + + QSqlQuery query; + query.prepare("INSERT INTO HVS_TAG2NODE (NODE_ID, TAG_NAME, TAG_ID, TAG_COMMENT, LOCKED, REPLICATED, DATE_CREATED, DATE_LOCKED, SUPPORTED)" + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); + query.bindValue(0, "0"); + query.bindValue(1, rootTag); + query.bindValue(2, newTag); + query.bindValue(3, QString()); + query.bindValue(4, "0"); + query.bindValue(5, "0"); + auto dt = QDateTime::currentMSecsSinceEpoch(); + query.bindValue(6, QString::number(dt)); + query.bindValue(7, QString()); + query.bindValue(8, m_tag2node->record(i).value("SUPPORTED").toString()); + if(!query.exec()) + { + cout<<query.lastError().text().toStdString()<<endl; + } + m_tag2node->select(); + + break; } + } +// submitChanges(m_tag2node); + if(!(/*m_tag2node->database().transaction() &&*/ m_tag2node->submitAll() && m_tag2node->database().commit())) + { + cout<<"Error editing tag2node when inserting new root tag\n Error: "; + cout<<m_tag2node->database().lastError().text().toStdString()<<endl; + } - //Edit tagcache - for(int i = 0; i < tagcache.rowCount(); i++) + //Edit tagcache + m_tagcache->select(); + for(int i = 0; i < m_tagcache->rowCount(); i++) + { + if(m_tagcache->record(i).value("ROOTTAG").toString() == replicateTagName) { - if(tagcache.record(i).value("ROOTTAG").toString() == replicateTag) + QSqlRecord record = m_tagcache->record(i); + record.setValue("ROOTTAG", rootTag); + if(m_tagcache->record(i).value("CHILDNODE").toString() == QString("FASER")) { - QSqlRecord record = tagcache.record(i); - record.setValue("ROOTTAG", rootTag); - - tagcache.insertRecord(-1, record); + record.setValue("CHILDTAG", rootTag); + record.setValue("CHILDTAGID", newTag); } + + m_tagcache->insertRecord(-1, record); } - tagcache.submitAll(); + } + submitChanges(m_tagcache); +/* if(!( m_tagcache->database().transaction() && m_tagcache->submitAll() && m_tagcache->database().commit())) + { + cout<<"Error editing tagcache when inserting new root tag\n Error: "; + cout<<m_tagcache->database().lastError().text().toStdString()<<endl; + }*/ + buildListWidget(); + m_rootDisplayTag = rootTag; + m_listWidget->setCurrentRow(m_listWidget->count()-1); + return newTag; +} +QString FaserDbMainWindow::createTag() +{ + //This function only works if used on root, or on a node whose parent has a unlocked tag + //Get tag we are creating under + QString nodeGettingTagName = selectedRowName(); + QString nodeGettingTagId = findAssociated( m_hvsNodeTableModel, QString("NODE_NAME"), nodeGettingTagName, QString("NODE_ID")); + QString newTag; + QString nullTag; + + bool ok = false; + + + int tagAvailable = 0; + for(int i = 0; i < m_tag2node->rowCount(); i++) + { + tagAvailable = (m_tag2node->record(i).value("TAG_ID").toString().toInt() > tagAvailable) ? m_tag2node->record(i).value("TAG_ID").toString().toInt() : tagAvailable; } + tagAvailable++; + newTag = QString::number(tagAvailable); + + //Case of adding tag to non root //Get list of unlocked parents - QStringList parentTags = findAssociatedList( <ag2ltag, QString("CHILD_NODE"), nodeGettingTagId, QString("PARENT_TAG")); + QStringList parentTags = findAssociatedList( m_ltag2ltag, QString("CHILD_NODE"), nodeGettingTagId, QString("PARENT_TAG")); for(int i = 0; i < parentTags.size(); i++) { - if( !isLocked(parentTags.at(i))) + if( isLocked(parentTags.at(i))) { parentTags.removeAt(i); i = 0; @@ -1082,10 +1734,7 @@ QString FaserDbMainWindow::createTag() //Case of no unlocked parent tags, can't add tag if(parentTags.empty()) { - QMessageBox messageBox;; - messageBox.critical(0, "Error", "No unlocked parent tags to choose from"); - messageBox.setFixedSize(500,200); - messageBox.exec(); + errorMessage("No unlocked parent tags to choose from"); return nullTag; } @@ -1093,10 +1742,10 @@ QString FaserDbMainWindow::createTag() QStringList parentTagNames; for(int i = 0; i < parentTags.size(); i++) { - parentTagNames.push_back( findAssociated( &tag2node, QString("TAG_ID"), parentTags.at(i), QString("TAG_NAME"))); + parentTagNames.push_back( findAssociated( m_tag2node, QString("TAG_ID"), parentTags.at(i), QString("TAG_NAME"))); } QString parentTagName = QInputDialog::getItem(this, tr("QInputDialog::getItem()"), tr("Unlocked tag to set as parent of new tag:"), parentTagNames, 0, false, &ok); - QString parentTag = findAssociated(&tag2node, QString("TAG_NAME"), parentTagName, QString("TAG_ID")); + QString parentTag = findAssociated(m_tag2node, QString("TAG_NAME"), parentTagName, QString("TAG_ID")); if(!ok) { //user exited choosing @@ -1105,16 +1754,19 @@ QString FaserDbMainWindow::createTag() } //Now we need to choose an existing tag ours will be a copy of - QStringList currentTags = findAssociatedList( &tag2node, QString("NODE_ID"), nodeGettingTagId, QString("TAG_ID")); - QString copyTag = QInputDialog::getItem(this, tr("QInputDialog::getItem()"), tr("Choose tag to initialize as copy of:"), currentTags, 0, false, &ok); + QStringList currentTags = findAssociatedList( m_tag2node, QString("NODE_ID"), nodeGettingTagId, QString("TAG_NAME")); + QString copyTagName = QInputDialog::getItem(this, tr("QInputDialog::getItem()"), tr("Choose tag to initialize as copy of:"), currentTags, 0, false, &ok); if( !ok) {//user closed window cout<<"No tag to copy passed through\n"; return nullTag; } + QString copyTag = findAssociated(m_tag2node, QString("TAG_NAME"), copyTagName, QString("TAG_ID")); + QString parentName = findAssociated(m_tagcache, QString("CHILDTAG"), parentTagName, QString("CHILDNODE")); //Lastly get name of new tag - QString newTagName = QInputDialog::getText(this, tr("QInputDialog::getText()"), tr("New Tag name:"), QLineEdit::Normal, parentTag, &ok); + QString temp = parentTagName; + QString newTagName = QInputDialog::getText(this, tr("QInputDialog::getText()"), tr("New Tag name:"), QLineEdit::Normal, temp.replace(parentName, nodeGettingTagName), &ok); if( !ok || currentTags.contains(newTagName)) { cout<<"Failed to get new tag name/input repeated tag name\n"; @@ -1123,67 +1775,283 @@ QString FaserDbMainWindow::createTag() //Now we edit the three tables, inserting our new tag //Edit ltag2ltag - for(int i = 0; i < ltag2ltag.rowCount(); i++) + if(!m_ltag2ltag->database().transaction()) + { + cout<<"failed transaction : "<<m_ltag2ltag->database().lastError().text().toStdString()<<endl; + } + for(int i = 0; i < m_ltag2ltag->rowCount(); i++) { - if(ltag2ltag.record(i).value("PARENT_TAG").toString() == parentTag - && ltag2ltag.record(i).value("CHILD_TAG").toString() == copyTag) + if(m_ltag2ltag->record(i).value("PARENT_TAG").toString() == parentTag + && m_ltag2ltag->record(i).value("CHILD_TAG").toString() == copyTag) { - ltag2ltag.record(i).setValue("CHILD_TAG", newTag); + m_ltag2ltag->record(i).setValue("CHILD_TAG", newTag); } - if(ltag2ltag.record(i).value("PARENT_TAG").toString() == copyTag) + if(m_ltag2ltag->record(i).value("PARENT_TAG").toString() == copyTag) { - QSqlRecord record = ltag2ltag.record(i); + QSqlRecord record = m_ltag2ltag->record(i); record.setValue("PARENT_TAG", newTag); - ltag2ltag.insertRecord(-1, record); + m_ltag2ltag->insertRecord(-1, record); } } +// submitChanges(m_ltag2ltag); + if(!( /*m_ltag2ltag->database().transaction() &&*/ m_ltag2ltag->submitAll() && m_ltag2ltag->database().commit())) + { + cout<<"Error editing ltag2ltag when inserting tag\n Error: "; + cout<<m_ltag2ltag->database().lastError().text().toStdString()<<endl; + } //Edit tag2node - for(int i = 0; i < tag2node.rowCount(); i++) + if(!( m_tag2node->database().transaction())) { - if(tag2node.record(i).value("TAG_ID").toString() == copyTag) + cout<<"Error starting transaction : "<<m_tag2node->database().lastError().text().toStdString()<<endl; + } + + for(int i = 0; i < m_tag2node->rowCount(); i++) + { + if(m_tag2node->record(i).value("TAG_ID").toString() == copyTag) { - QSqlRecord record = tag2node.record(i); +/* QSqlRecord record = m_tag2node->record(i); record.setNull("TAG_COMMENT"); record.setValue("LOCKED", QString("0")); record.setValue("REPLICATED", QString("0")); record.setValue("TAG_NAME", newTagName); + record.setValue("TAG_ID", newTag); record.setNull("DATE_LOCKED"); auto dt = QDateTime::currentMSecsSinceEpoch(); record.setValue("DATE_CREATED", QString::number(dt)); - tag2node.insertRecord(-1, record); + if(!m_tag2node->insertRecord(-1, record)) + { + cout<<"failed to insert tag2node record?\n"; + cout<<m_tag2node->lastError().text().toStdString()<<endl; + }*/ + + QSqlQuery query; + query.prepare("INSERT INTO HVS_TAG2NODE (NODE_ID, TAG_NAME, TAG_ID, TAG_COMMENT, LOCKED, REPLICATED, DATE_CREATED, DATE_LOCKED, SUPPORTED)" + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); + query.bindValue(0, m_tag2node->record(i).value("NODE_ID").toString()); + query.bindValue(1, newTagName); + query.bindValue(2, newTag); + query.bindValue(3, QString()); + query.bindValue(4, "0"); + query.bindValue(5, "0"); + auto dt = QDateTime::currentMSecsSinceEpoch(); + query.bindValue(6, QString::number(dt)); + query.bindValue(7, QString()); + query.bindValue(8, m_tag2node->record(i).value("SUPPORTED").toString()); + if(!query.exec()) + { + cout<<query.lastError().text().toStdString()<<endl; + } + m_tag2node->select(); + + break; + } + } +// submitChanges(m_tag2node); + if(!( /*m_tag2node->database().transaction() &&*/ m_tag2node->submitAll() && m_tag2node->database().commit())) + { + cout<<"Error editing tag2node when inserting tag\n Error: "; + cout<<m_tag2node->database().lastError().text().toStdString()<<endl; + } + + //Edit tagcache + QString rootTag = findAssociated( m_tagcache, QString("CHILDTAG"), parentTagName, QString("ROOTTAG")); + if(!m_tagcache->database().transaction()) + { + cout<<"Error starting tagcache transaction : "<<m_tagcache->database().lastError().text().toStdString()<<endl; + } + for(int i = 0; i < m_tagcache->rowCount(); i++) + { + if(m_tagcache->record(i).value("CHILDTAGID").toString() == copyTag + && m_tagcache->record(i).value("ROOTTAG").toString() == rootTag) + { + QSqlRecord record = m_tagcache->record(i); + record.setValue("CHILDTAG", newTagName); + record.setValue("CHILDTAGID", newTag); + + m_tagcache->setRecord(i, record); + break; + } + } +// submitChanges(m_tagcache); + if(!( /*m_tagcache->database().transaction() &&*/ m_tagcache->submitAll() && m_tagcache->database().commit())) + { + cout<<"Error editing tagcache when inserting tag\n Error: "; + cout<<m_tagcache->database().lastError().text().toStdString()<<endl; + } + + //If we are working on a leaf node, also need to add new rows into correponding _DATA2TAG tables + QString name = selectedRowName(); + name.append("_DATA2TAG"); + QSqlTableModel data2tag; + data2tag.setTable(name); + data2tag.select(); + + for(int i = 0; i <data2tag.rowCount(); i++) + { + if(data2tag.record(i).value(0).toString() == copyTag) + { + QSqlRecord record = data2tag.record(i); + record.setValue(0, newTag); + + data2tag.insertRecord(-1, record); + } + } + submitChanges(&data2tag); + + + + rebuildTree(); + return newTag; +} + +//Function locks a tag. If the tag is a parent it recursively locks all children tags too +void FaserDbMainWindow::lockTag(QString toLock) +{ + bool original = false; + //If function was called by action menu need to get tag to lock + if( toLock.isNull()) + { + original = true; + QString currentRow = m_currentSelected; + if(currentRow.endsWith("_DATA") || currentRow.endsWith("_DATA2TAG")) + { + cout<<"Tried to lock tag at _DATA or _DATA2TAG level\n"; + return; + } + + //Get list of unlocked tags associated with current table + //We want to show the user the names of tags, not tags themself + QStringList tagNames = findAssociatedList(m_tag2node, QString("NODE_ID"), findAssociated(m_hvsNodeTableModel, QString("NODE_NAME"), currentRow, QString("NODE_ID")), QString("TAG_NAME")); + for(int i = 0; i < tagNames.size(); i++) + { + if( isLocked(findAssociated(m_tag2node, QString("TAG_NAME"), tagNames.at(i), QString("LOCKED")))) + { + tagNames.removeAt(i); + i--; + } + } + //We want to show the user the names of tags, not tags themself + bool ok; + QString toLockName = QInputDialog::getItem(this, tr("QInputDialog::getItem()"), tr("Choose tag to lock:"), tagNames, 0, false, &ok); + if(!ok) + { + cout<<"Failed to get tag to lock from user\n"; + return; } + toLock = findAssociated(m_tag2node, QString("TAG_NAME"), toLockName, QString("TAG_ID")); } - //Edit tagcache - QString rootTag = findAssociated( &tagcache, QString("CHILDTAG"), parentTagName, QString("ROOTTAG")); - for(int i = 0; i < tagcache.rowCount(); i++) - { - if(tagcache.record(i).value("CHILDTAGID").toString() == copyTag - && tagcache.record(i).value("ROOTTAG").toString() == rootTag) + //Lock tag and recursively call for each child tag + for(int i = 0; i < m_tag2node->rowCount(); i++) + { + if(m_tag2node->record(i).value("TAG_ID").toString() == toLock) + { + if(!m_tag2node->database().transaction()) + { + cout<<"Error starting transaction in locking tag : "<<m_tag2node->database().lastError().text().toStdString()<<endl; + } + QModelIndex index = m_tag2node->index(i, 4); + m_tag2node->setData(index, QString("1")); + index = m_tag2node->index(i, 7); + auto dt = QDateTime::currentMSecsSinceEpoch(); + m_tag2node->setData(index, QString::number(dt)); +/* submitChanges(m_tag2node); + m_tag2node->database().transaction(); + m_tag2node->submitAll(); + m_tag2node->database().commit();*/ + if(!( m_tag2node->submitAll() && m_tag2node->database().commit())) + { + cout<<"Error locking tags : "<<m_tag2node->database().lastError().text().toStdString()<<endl; + } + + QStringList toLockList = findAssociatedList(m_ltag2ltag, QString("PARENT_TAG"), toLock, QString("CHILD_TAG")); + for(int i = 0; i < toLockList.size(); i++) + { + lockTag(toLockList.at(i)); + } + break; + } + } + + if(original) + { + + if(!(m_tag2node->database().transaction() && m_tag2node->submitAll() && m_tag2node->database().commit())) + { + cout<<"Error editing tag2node when inserting locking tags tag\n Error: "; + cout<<m_tag2node->database().lastError().text().toStdString()<<endl; + } + m_secondWindow->clearWindow(); + rebuildTree(); + m_secondWindow->setWindow(m_currentSelected); + } + return; +} + +//Function commits changes to database; +bool FaserDbMainWindow::submitChanges(QSqlTableModel *table) +{ + if(! (table->database().transaction() && table->submitAll() && table->database().commit())) + { + cout<<"Error submitting changes to table "<<table->tableName().toStdString()<<endl; + cout<<table->lastError().text().toStdString()<<endl; + cout<<table->database().lastError().text().toStdString()<<endl; + return false; + } + table->select(); + return true; +} + + +void FaserDbMainWindow::errorMessage(string message) +{ + +// QMessageBox messageBox; + QMessageBox::critical(0, "Error", QString::fromStdString(message)); +// messageBox.setFixedSize(500,200); +// messageBox.exec(); +} + +void FaserDbMainWindow::buildListWidget() +{ + m_listWidget->clearSelection(); + m_listWidget->clearFocus(); + m_listWidget->clear(); + new QListWidgetItem(QString("No root tag set"), m_listWidget); +// QSQlTableModel model; +// model.setTable("HVS_TAG2NODE"); +// model.select(); + for(int i = 0; i < m_tag2node->rowCount(); i++) + { + if(m_tag2node->record(i).value("NODE_ID").toString() == "0") { - tagcache.record(i).setValue("CHILDTAG", newTagName); - tagcache.record(i).setValue("CHILDTAGID", newTag); + new QListWidgetItem(m_tag2node->record(i).value("TAG_NAME").toString(), m_listWidget); } } - - ltag2ltag.submitAll(); - tag2node.submitAll(); - tagcache.submitAll(); - - return newTag; } -void FaserDbMainWindow::errorMessage(string message) +void FaserDbMainWindow::tagRowChanged(int currentRow) { + if(currentRow <= 0) + { + QString nullstr; + m_rootDisplayTag = nullstr; + m_secondWindow->clearWindow(); + rebuildTree(); + return; + } + else + { + m_rootDisplayTag = m_listWidget->item(currentRow)->text(); + m_secondWindow->clearWindow(); + rebuildTree(); + return; + } - QMessageBox messageBox; - messageBox.critical(0, "Error", QString::fromStdString(message)); - messageBox.setFixedSize(500,200); - messageBox.exec(); } /* @@ -1201,7 +2069,8 @@ void FaserDbSecondWindow::submit() if(m_tableModel->submitAll()) { m_tableModel->database().commit(); - m_parentWindow->rebuildTree(); +//This function should only be called when we edit _DATA or _DATA2TAG, so no need to rebuild +// m_parentWindow->rebuildTree(); } else { @@ -1213,17 +2082,89 @@ void FaserDbSecondWindow::submit() void FaserDbSecondWindow::addRow() { - if(!m_tableModel->insertRows(m_tableView->selectionModel()->currentIndex().row() + 1, 1)) +/* QSqlRecord record; + record = m_tableModel->record(0); + if(!m_parentWindow->m_rootDisplayTag.isNull()) + { + for(int i = 0; i < m_parentWindow->m_tagcache->rowCount(); i++) + { + if(m_parentWindow->m_tagcache->record(i).value("ROOTTAG").toString() == m_parentWindow->m_rootDisplayTag + && m_parentWindow->m_tagcache->record(i).value("CHILDNODE").toString() == m_parentWindow->m_rootDisplayTag) + } + record.setValue(0, ) + }*/ + + //Cant add row if its to a locked table + if(!m_parentWindow->m_rootDisplayTag.isNull()) + { + QString nodeName = m_parentWindow->selectedRowName(); + if(nodeName.endsWith("_DATA")) + { + nodeName.remove("_DATA"); + } + else + { + nodeName.remove("_DATA2TAG"); + } + for(int i = 0; i < m_parentWindow->m_tagcache->rowCount(); i++) + { + if(m_parentWindow->m_tagcache->record(i).value("ROOTTAG").toString() == m_parentWindow->m_rootDisplayTag + && m_parentWindow->m_tagcache->record(i).value("CHILDNODE").toString() == nodeName) + { + if(m_parentWindow->isLocked(m_parentWindow->m_tagcache->record(i).value("CHILDTAGID").toString())) + { + m_parentWindow->errorMessage("Table is currently associated with locked tag"); + return; + } + else + { + break; + } + } + } + } + if(m_tableView->selectionModel()->currentIndex().isValid()) + { + m_tableModel->insertRows(m_tableView->selectionModel()->currentIndex().row() + 1, 1); + } + else { - //This executes only if there was no valid index, and then puts a new row at beginning - m_tableModel->insertRows(0, 1); + //This executes only if there was no valid index, and then puts a new row at the end + m_tableModel->insertRows(m_tableModel->rowCount(), 1); } } void FaserDbSecondWindow::addColumn() { + //Cant add column if any of the associated tags are locked + QString nodeName = m_parentWindow->selectedRowName(); + if(nodeName.endsWith("_DATA")) + { + nodeName.remove("_DATA"); + } + else + { + m_parentWindow->errorMessage("Cannot add columns to data2tag tables"); + return; + } + for(int i = 0; i < m_parentWindow->m_tagcache->rowCount(); i++) + { + if( m_parentWindow->m_tagcache->record(i).value("CHILDNODE").toString() == nodeName) + { + if(m_parentWindow->isLocked(m_parentWindow->m_tagcache->record(i).value("CHILDTAGID").toString())) + { + m_parentWindow->errorMessage("Cannot add a column to a table associated with a locked tag"); + return; + } + else + { + break; + } + } + } + bool oktext; - QString text = QInputDialog::getText(this, tr("QInputDialog::getText()"), tr("New Table Name"), QLineEdit::Normal, QDir::home().dirName(),&oktext); + QString text = QInputDialog::getText(this, tr("QInputDialog::getText()"), tr("New Column Name"), QLineEdit::Normal, QString(),&oktext); bool oktype; QStringList types; @@ -1267,7 +2208,7 @@ void FaserDbSecondWindow::removeColumn() QString tagId = m_tableModel->record(i).value(0).toString(); if( m_parentWindow->isLocked(tagId)) { - cout<<"Trying to delete date from a locked column\n"; + cout<<"Trying to delete data from a locked column\n"; return; } } @@ -1346,75 +2287,26 @@ void FaserDbSecondWindow::removeColumn() void FaserDbSecondWindow::removeRow() { - m_tableModel->removeRows(m_tableView->selectionModel()->currentIndex().row(), 1); + m_sqlTableModel->removeRows(m_tableView->selectionModel()->currentIndex().row(), 1); +// m_tableModel->removeRows(m_tableView->selectionModel()->currentIndex().row(), 1); +//Hide row/reshow if revert later +// m_tableView->hideRow(m_tableView->selectionModel()->currentIndex().row()); } FaserDbSecondWindow::FaserDbSecondWindow(FaserDbMainWindow *window_parent, QWidget* parent) : QWidget(parent) - , m_tableModel(new QSqlRelationalTableModel(nullptr, window_parent->returnDatabase())) + , m_tableModel(new FaserDbRelTableModel(nullptr, window_parent->returnDatabase(), this)) + , m_tagTable(new QSqlTableModel(nullptr, window_parent->returnDatabase() )) + , m_sqlTableModel(new QSqlTableModel(nullptr, window_parent->returnDatabase())) /* , m_standardModel(new QStandardItemModel(this))*/ { // setCentralWidget(m_tableModel); m_tableView = nullptr; m_parentWindow = window_parent; -/* m_tableModel->setTable("HVS_NODE"); - m_tableModel->setEditStrategy(QSqlTableModel::OnManualSubmit); - m_tableModel->select(); - - m_tableModel->setHeaderData(0, Qt::Horizontal, tr("NODE_ID")); - m_tableModel->setHeaderData(1, Qt::Horizontal, tr("NODE_NAME")); - m_tableModel->setHeaderData(2, Qt::Horizontal, tr("PARENT_ID")); - m_tableModel->setHeaderData(3, Qt::Horizontal, tr("BRANCH_FLAG")); - m_tableModel->setHeaderData(4, Qt::Horizontal, tr("CODE_COMMENT")); - - m_tableView = new QTableView; - m_tableView->setModel(m_tableModel); - m_tableView->resizeColumnsToContents(); - m_tableView->setMinimumWidth(500); - - m_submitButton = new QPushButton(tr("Submit")); - m_submitButton->setDefault(true); - m_revertButton = new QPushButton(tr("&Revert")); - m_quitButton = new QPushButton(tr("Quit")); - m_addRowButton = new QPushButton(tr("&Add Row")); - m_addColumnButton = new QPushButton(tr("&Add Column")); - m_removeColumn = new QPushButton(tr("&Remove Column")); - m_removeRow = new QPushButton(tr("&Remove Row")); - - m_buttonBox = new QDialogButtonBox(Qt::Vertical); - m_buttonBox->addButton(m_submitButton, QDialogButtonBox::ActionRole); - m_buttonBox->addButton(m_revertButton, QDialogButtonBox::ActionRole); - m_buttonBox->addButton(m_addRowButton, QDialogButtonBox::ActionRole); - m_buttonBox->addButton(m_addColumnButton, QDialogButtonBox::ActionRole); - m_buttonBox->addButton(m_removeColumn, QDialogButtonBox::ActionRole); - m_buttonBox->addButton(m_removeRow, QDialogButtonBox::ActionRole); - m_buttonBox->addButton(m_quitButton, QDialogButtonBox::RejectRole); - - connect(m_submitButton, &QPushButton::clicked, this, &FaserDbSecondWindow::submit); - connect(m_revertButton, &QPushButton::clicked, m_tableModel, &QSqlTableModel::revertAll); - connect(m_addRowButton, &QPushButton::clicked, this, &FaserDbSecondWindow::addRow); - connect(m_addColumnButton, &QPushButton::clicked, this, &FaserDbSecondWindow::addColumn); - connect(m_removeColumn, &QPushButton::clicked, this, &FaserDbSecondWindow::removeColumn); - connect(m_removeRow, &QPushButton::clicked, this, &FaserDbSecondWindow::removeRow); - connect(m_quitButton, &QPushButton::clicked, this, &FaserDbSecondWindow::close); - - QHBoxLayout *mainLayout = new QHBoxLayout(); - mainLayout->addWidget(m_tableView); - mainLayout->addWidget(m_buttonBox); - setLayout(mainLayout); - - setWindowTitle(tr("Edit Table"));*/ - - return; } -/* -QSqlTableModel* FaserDbSecondWindow::tablePointer() -{ - return m_tableModel; -}*/ void FaserDbSecondWindow::setWindow(QString tableName) { @@ -1425,24 +2317,60 @@ void FaserDbSecondWindow::setWindow(QString tableName) m_tableModel->setTable(tableName); m_tableModel->setEditStrategy(QSqlTableModel::OnManualSubmit); + m_sqlTableModel->setTable(tableName); + m_sqlTableModel->select(); + if( tableName.endsWith("_DATA2TAG") ) + { //Need to set relation table for tag table + m_tagTable->setTable(tableName); + m_tagTable->select(); + QSqlQuery query; + query.prepare("CREATE TABLE IF NOT EXISTS temp_tags (TAG_ID SLONGLONG UNIQUE, TAG_NAME TEXT UNIQUE)"); + query.exec(); + + QSqlTableModel model; + model.setTable("temp_tags"); + model.select(); + + QString nameless = tableName; + nameless.remove("_DATA2TAG"); + for(int i = 0; i < m_parentWindow->m_tagcache->rowCount(); i++) + { + if(m_parentWindow->m_tagcache->record(i).value("CHILDNODE").toString() == nameless ) +// && (m_parentWindow->m_rootDisplayTag.isNull() || m_parentWindow->m_tagcache->record(i).value("ROOTTAG").toString() == m_parentWindow->m_rootDisplayTag)) + { + QSqlRecord record = model.record(); + record.setValue("TAG_ID", m_parentWindow->m_tagcache->record(i).value("CHILDTAGID").toString()); + record.setValue("TAG_NAME", m_parentWindow->m_tagcache->record(i).value("CHILDTAG").toString()); + + if(!model.insertRecord(-1, record)) + { + cout<<"inserting record failed for temp tags\n"; + } + } + } + + + + m_tableModel->setRelation(0, QSqlRelation("temp_tags", "TAG_ID", "TAG_NAME")); + } + else { - m_tableModel->setRelation(0, QSqlRelation("HVS_TAG2NODE", "TAG_ID", "TAG_NAME")); + QString name = tableName; + name.append("2TAG"); + m_tagTable->setTable(name); + m_tagTable->select(); } m_tableModel->select(); -/* m_tableModel->setHeaderData(0, Qt::Horizontal, tr("NODE_ID")); - m_tableModel->setHeaderData(1, Qt::Horizontal, tr("NODE_NAME")); - m_tableModel->setHeaderData(2, Qt::Horizontal, tr("PARENT_ID")); - m_tableModel->setHeaderData(3, Qt::Horizontal, tr("BRANCH_FLAG")); - m_tableModel->setHeaderData(4, Qt::Horizontal, tr("CODE_COMMENT")); */ - m_tableView = new QTableView; m_tableView->setModel(m_tableModel); m_tableView->resizeColumnsToContents(); m_tableView->setMinimumWidth(500); + m_tableView->setItemDelegate(new QSqlRelationalDelegate(m_tableView)); + m_submitButton = new QPushButton(tr("Submit")); m_submitButton->setDefault(true); m_revertButton = new QPushButton(tr("&Revert")); @@ -1476,6 +2404,72 @@ void FaserDbSecondWindow::setWindow(QString tableName) setWindowTitle(tableName); + //Code to deal with when we have a tag filter set + if( !m_parentWindow->m_rootDisplayTag.isNull()) + { + QSqlTableModel tagcache(nullptr, m_parentWindow->returnDatabase()); + tagcache.setTable("HVS_TAGCACHE"); + tagcache.select(); + QString nodeName = m_parentWindow->selectedRowName(); + if(nodeName.endsWith("_DATA")) + { + nodeName.remove("_DATA"); + } + else + { + nodeName.remove("_DATA2TAG"); + } + + //Need to find the tag for our current table under given root tag + for(int i = 0; i < tagcache.rowCount(); i++) + { + if(tagcache.record(i).value("ROOTTAG").toString() == m_parentWindow->m_rootDisplayTag + && tagcache.record(i).value("CHILDNODE").toString() == nodeName) + { + setTagFilter(tagcache.record(i).value("CHILDTAGID").toString()); + break; + } + } + } + + //Build isSelectable bool vector to maintain if editable/uneditable + if(tableName.endsWith("_DATA2TAG")) + { + for(int i = 0; i < m_tagTable->rowCount(); i++) + { + m_isLocked.push_back(m_parentWindow->isLocked(m_tagTable->record(i).value(0).toString())); + } + } + else + { + for(int i = 0; i < m_sqlTableModel->rowCount(); i++) + { + if(m_sqlTableModel->record(i).value(0).toString().isNull()) + { + continue; + } + int j = 0; + for(; j < m_tagTable->rowCount(); j++) + { + if(m_tagTable->record(j).value(1).toString().isNull() || m_tagTable->record(j).value(0).toString().isNull()) + { + continue; + } +// cout<<"Checking "<<m_sqlTableModel->record(i).value(0).toString().toStdString()<<" "<< m_tagTable->record(j).value(1).toString().toStdString()<<endl; + if( m_sqlTableModel->record(i).value(0).toString() == m_tagTable->record(j).value(1).toString()) + { + m_isLocked.push_back(m_parentWindow->isLocked(m_tagTable->record(j).value(0).toString())); + j = -1; + break; + } + } + if(j != -1) + { + m_isLocked.push_back(false); + } + } + } + } @@ -1483,7 +2477,11 @@ void FaserDbSecondWindow::clearWindow() { if(m_tableView != nullptr) { + QSqlQuery query; + query.prepare("DROP TABLE IF EXISTS temp_tags"); + query.exec(); delete layout(); + m_isLocked.clear(); delete m_submitButton; delete m_revertButton; delete m_quitButton; @@ -1497,52 +2495,6 @@ void FaserDbSecondWindow::clearWindow() } } -//Following fucntion is reimplementation of flags function -//Reimplemented to return a non-editable flag for rows where data is locked -Qt::ItemFlags testtest::flags(const QModelIndex &index) const -{ -Qt::ItemFlags flags; - -// flags = QAbstractItemModel::flags(index); - cout<<"hello\n"; - if(index.isValid()) - { - } -/* QString tableName = m_parentWindow->selectedRowName(); - int row = m_tableView->selectionModel()->currentIndex().row(); - if( !tableName.endsWith("_DATA2TAG")) - { - if( tableName.endsWith("_DATA")) - { - tableName.append("2TAG"); - } - else - { - tableName.append("_DATA2TAG"); - } - } - - //Get current data id we are looking at - cout<<m_tableModel->record(row).value(0).toString().toStdString()<<endl; - cout<<row<<endl; - - QSqlTableModel tagTable; - tagTable.setTable(tableName); - tagTable.select(); - - QString tagId = tagTable.record(row).value(0).toString(); - - if( m_parentWindow->isLocked(tagId)) - { -// flags = Qt::ItemIsSelectable; - return Qt::ItemIsSelectable; - } -*/ - return Qt::ItemIsEditable; - - -} - void FaserDbSecondWindow::click_cell(int row, int column) { cout<<row<<column<<endl; @@ -1556,12 +2508,10 @@ void FaserDbSecondWindow::setTagFilter(QString tagFilter) //Case where we are looking at the tag table if(currentNode.endsWith("_DATA2TAG")) { - QSqlTableModel data2tagtable; - data2tagtable.setTable(currentNode); - data2tagtable.select(); - for(int i = 0; i < data2tagtable.rowCount(); i++) + //Old code for when we didnt use temp tags relational table, automatically filters now for _DATA2TAG tables + for(int i = 0; i < m_tagTable->rowCount(); i++) { - if(data2tagtable.record(i).value(0).toString() != tagFilter) + if(m_tagTable->record(i).value(0).toString() != tagFilter) { m_tableView->hideRow(i); } @@ -1572,23 +2522,12 @@ void FaserDbSecondWindow::setTagFilter(QString tagFilter) //Case where we are looking at data table //Need to get a vector of data id's we will permit vector<QString> nodeIds; - if(currentNode.endsWith("_DATA")) - { - currentNode.append("2TAG"); - } - else - { - currentNode.append("_DATA2TAG"); - } - QSqlTableModel data2TagTable; - data2TagTable.setTable(currentNode); - data2TagTable.select(); - for(int i = 0; i < data2TagTable.rowCount(); i++) + for(int i = 0; i < m_tagTable->rowCount(); i++) { - if( data2TagTable.record(i).value(0).toString() == tagFilter) + if( m_tagTable->record(i).value(0).toString() == tagFilter) { - nodeIds.push_back(data2TagTable.record(i).value(1).toString()); + nodeIds.push_back(m_tagTable->record(i).value(1).toString()); } } @@ -1609,4 +2548,133 @@ void FaserDbSecondWindow::setTagFilter(QString tagFilter) } +//Destructor to delete temp tags table used for our relational table model +FaserDbSecondWindow::~FaserDbSecondWindow() +{ + clearWindow(); +} + +FaserDbRelTableModel::FaserDbRelTableModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase(), FaserDbSecondWindow *secondWin = nullptr) +{ + m_secondWindow = secondWin; + (void)parent; + (void)db; +} + +//Following function override recolors rows based off of if they are associated with locked rows +//Red = locked, yellow = doubley locked, green = unlocked +QVariant FaserDbRelTableModel::data(const QModelIndex &idx, int role) const +{ + QVariant var = QSqlRelationalTableModel::data(idx, role); + + if( role == Qt::BackgroundRole) + { + //Case where this is a data2tag table + FaserDbMainWindow *main = m_secondWindow->m_parentWindow; + if(this->tableName().endsWith("_DATA2TAG")) + { + QString curtag = main->findAssociated(main->m_tagcache, QString("CHILDTAG"), this->record(idx.row()).value(0).toString(), QString("CHILDTAGID")); + return (main->isLocked(curtag)) ? QVariant(QColor(Qt::red)) : QVariant(QColor(Qt::green)); + } + else //Case where it is a data table + { + //Need a list of associated tags with current data id + QString curDatId = this->record(idx.row()).value(0).toString().toUpper(); + QString dataName = this->tableName().replace("_DATA", "_DATA_ID").toUpper(); + QString tagName = this->tableName().replace("_DATA", "_TAG_ID").toUpper(); + QStringList tags = main->findAssociatedList(m_secondWindow->m_tagTable, dataName, curDatId, tagName); + if(tags.size() == 0) + { + return QVariant(QColor(Qt::white)); + } + else + { + if( tags.size() == 1) + { + return (main->isLocked(tags.at(0))) ? QVariant(QColor(Qt::red)) : QVariant(QColor(Qt::green)); + } + int numNotLocked = 0; + for(int i = 0; i < tags.size(); i++) + { + if(main->isLocked(tags.at(0))) + { + return QVariant(QColor(Qt::red)); + } + numNotLocked++; + } + if(numNotLocked == 1) + { + return QVariant(QColor(Qt::green)); + } + else + { + return QVariant(QColor(Qt::yellow)); + } + + } + } + } + + return var; +} + +//x +//Following fucntion is reimplementation of flags function +//Reimplemented to return a non-editable flag for rows where data is locked +Qt::ItemFlags FaserDbRelTableModel::flags(const QModelIndex &index) const +{ +Qt::ItemFlags flags; + + flags = QAbstractItemModel::flags(index); + int row = index.row(); +/* QString tagId; + + //If tag table + if(m_secondWindow->m_sqlTableModel->tableName().endsWith("_DATA2TAG")) + { + tagId = m_secondWindow->m_parentWindow->findAssociated(m_secondWindow->m_parentWindow->m_tag2node, QString("TAG_NAME"), + record(row).value(0).toString(), QString("TAG_ID")); + } + else //If data, want associated tag number + { + if( !record(row).value(0).toString().isNull()) + { +// tagId = m_secondWindow->m_parentWindow->findAssociated(m_secondWindow->m_parentWindow->m_tagTable, QString("TAG_NAME"), +// record(row).value(0).toString(), QString("TAG_ID")); + for(int i = 0; i < m_secondWindow->m_tagTable->rowCount(); i++) + { + if(m_secondWindow->m_tagTable->record(i).value(1).toString() == record(row).value(0).toString()) + { + tagId = m_secondWindow->m_tagTable->record(i).value(0).toString(); + if(m_secondWindow->m_parentWindow->isLocked(tagId)) + { + flags = flags & ~Qt::ItemIsEditable; + return flags; + } + } + } + } + } + + + if( !m_secondWindow->m_parentWindow->isLocked(tagId) || tagId.isNull()) + { + flags |= Qt::ItemIsEditable; + }*/ + if(m_secondWindow->m_isLocked[row]) + { + flags = flags & ~Qt::ItemIsEditable; + } + else + { + flags |= Qt::ItemIsEditable; + } + + return flags; + + +} + + +