From 1fb5b30e665f520b46df49caceb28d3c9422a8ff Mon Sep 17 00:00:00 2001
From: Ryan Alexander Rice-Smith <rricesmi@uci.edu>
Date: Wed, 5 Feb 2020 06:01:34 +0000
Subject: [PATCH] Replace FaserDbMainWindow.cxx

---
 .../FaserGeoEditor/src/FaserDbMainWindow.cxx  | 1956 +++++++++++++----
 1 file changed, 1512 insertions(+), 444 deletions(-)

diff --git a/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserDbMainWindow.cxx b/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserDbMainWindow.cxx
index 93dab3b9..133cd546 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(&ltag2ltag, 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( &ltag2ltag, 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;
+
+
+}
+
+
+
 
-- 
GitLab