diff --git a/DetectorDescription/GeoModel/FaserGeoEditor/README.md b/DetectorDescription/GeoModel/FaserGeoEditor/README.md
index edf8be68cfa3e1c244c0d30c78eefd760d0e8f4d..65918dd870b85a5cab71712cd9c53779c881cd14 100644
--- a/DetectorDescription/GeoModel/FaserGeoEditor/README.md
+++ b/DetectorDescription/GeoModel/FaserGeoEditor/README.md
@@ -1,21 +1,27 @@
 # FaserGeoEditorApp
 Qt Application for editing and maintaining the Faser GeoModel Sql Database
 
-
-These are subfiles within larger repository https://gitlab.cern.ch//dcasper/calypso
-
-Requires entire calypso repository to run/compile currently
-
-Replace files found in calypso/DetectorDescription/GeoModel/FaserGeoEditor/src with these files
-
 After following calypso readme to build all files:
 
 cd ../run
 
 source ./setup.sh
 
-FaserGeoEditor data/geomDB_sqlite
+The program can currently read a sql file of text commands, or a sql binary file. To differentiate between the file being read, add a third argument to call the program of t for text, b for binary
+Note: it cannot read sqlite files currently
+
+ex:
+FaserGeoEditor data/geomDB.sql t
 
 Adding rows/columns adds one after the selected index (if none selected inputs new one at beginning)
 
 Changes to table are only saved if submitted
+
+While open the file, along with changes will continuously saved to a binary file GeoEditorSqlite
+
+To finalize the file and resave as a text file, ctrl+s or save in the menu will allow for this
+
+Color coding : 
+	green -associated with an unlocked tag; data can be edited and children tags can be created(if branch)
+	yellow -associated with a doubly unlocked tag; in general this can lead to unwanted behaviour, and may cause issues if continued. When one of the tags associated is later locked, it will still lock the data but can lead to issues with child tag creations
+	red -associated with a locked tag. Data cannot be edited and child tags cannot be added. To change data or create children, need to create a new tag at this level that is a copy of the version desired, then create children.
diff --git a/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserDbMainWindow.cxx b/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserDbMainWindow.cxx
index 93dab3b9fb788b99af14e3e2d0d7d2b6e4f6353b..133cd546ec5356584fdb3ba64d088043f2e60af7 100644
--- a/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserDbMainWindow.cxx
+++ b/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserDbMainWindow.cxx
@@ -13,54 +13,20 @@
 #include <QVariant>
 #include <QSqlField>
 #include <vector>
+#include <QtGui>
+#include <QTextStream>
 
 using namespace std;
 
-FaserDbMainWindow::FaserDbMainWindow(QWidget* parent)
+FaserDbMainWindow::FaserDbMainWindow(QWidget* parent, FaserGeoEditorApp *parentApp)
     : QMainWindow(parent)
     , m_treeView(new QTreeView(this))
     , m_standardModel(new QStandardItemModel(this))
 {
+    m_editorApp = parentApp;
     showMaximized();
-/*    setCentralWidget(m_treeView);
-
-    QStandardItem* root = m_standardModel->invisibleRootItem();
-
-    QSqlTableModel *m_model = new QSqlTableModel(nullptr, m_database);
-    m_model->setTable("HVS_NODE");
-    m_model->select();
-    
-    QList<QStandardItem*> firstRow;
-    for( int i = 0; i < m_model->record(0).count(); i++)
-    {
-        QStandardItem *temp = new QStandardItem(m_model->record(0).value(i).toString());
-        firstRow.push_back(temp);
-    }
-    
-    root->appendRow(firstRow);
-    QList<QStandardItem*> subRow = prepareRow( m_model->record(2).value(0).toString(), m_model->record(2).value(1).toString(), m_model->record(2).value(2).toString(), m_model->record(2).value(3).toString(), m_model->record(2).value(4).toString() );
-    firstRow.first()->appendRow(subRow);*/
-
-//    auto tables = m_database.tables();
-//    for (auto it = tables.constBegin(); it != tables.constEnd(); ++it) std::cout << (*it).toLocal8Bit().constData() << std::endl;
-
-/*    QList<QStandardItem*> firstRow = prepareRow("name 1", "leaf 1");
-    root->appendRow(firstRow);
-    QList<QStandardItem*> secondRow = prepareRow("name 2", "leaf 2");
-    root->appendRow(secondRow);
-    QList<QStandardItem*> subRow = prepareRow("subName 1", "subLeaf 1");
-    firstRow.first()->appendRow(subRow);*/
-
- //   m_treeView->setModel(m_standardModel);
-   // m_treeView->expandAll();
 }
 
-// FaserDbMainWindow::~FaserDbMainWindow()
-// {
-//     if (m_standardModel != nullptr) delete m_standardModel;
-//     if (m_treeView != nullptr) delete m_treeView;
-// }
-
 
 QList<QStandardItem*> FaserDbMainWindow::prepareRow(  const QString& name1, const QString& name2, const QString& name3, const QString& name4, const QString& name5)
 {
@@ -84,17 +50,33 @@ void FaserDbMainWindow::setDatabase( QSqlDatabase *db)
     m_hvsNodeTableModel = new QSqlTableModel(nullptr, m_database);
     m_hvsNodeTableModel->setTable("HVS_NODE");
     m_hvsNodeTableModel->select();
+    m_tag2node = new QSqlTableModel(nullptr, m_database);
+    m_tag2node->setTable("HVS_TAG2NODE");
+    m_tag2node->select();
+    m_tagcache = new QSqlTableModel(nullptr, m_database);
+    m_tagcache->setTable("HVS_TAGCACHE");
+    m_tagcache->select();
+    m_ltag2ltag = new QSqlTableModel(nullptr, m_database);
+    m_ltag2ltag->setTable("HVS_LTAG2LTAG");
+    m_ltag2ltag->select();
     return;
 }
 
 void FaserDbMainWindow::initializeWindow()
 {
-    //Build second window
+    //Build second window and third window
     QDockWidget *secondWid = new QDockWidget(tr("Data"), this);
+    QDockWidget *thirdWid = new QDockWidget(tr("Root Tags"), this);
     secondWid->setAllowedAreas(Qt::RightDockWidgetArea);
+    thirdWid->setAllowedAreas(Qt::LeftDockWidgetArea);
     m_secondWindow = new FaserDbSecondWindow(this, secondWid);
+    m_listWidget = new QListWidget(this);
+//    m_thirdWindow = new FaserDbMainWindow(this, thirdWid);
     secondWid->setWidget(m_secondWindow);
+    thirdWid->setWidget(m_listWidget);
     addDockWidget(Qt::RightDockWidgetArea, secondWid);
+    addDockWidget(Qt::LeftDockWidgetArea, thirdWid);
+    m_listWidget->setSelectionMode(QAbstractItemView::SingleSelection);
 
     setCentralWidget(m_treeView);
 
@@ -114,10 +96,10 @@ void FaserDbMainWindow::initializeWindow()
     createStatusBar();
 
     QSqlTableModel *model = m_hvsNodeTableModel;
-    
+
     for(int i = 0; i < model->rowCount(); i++)
     {
-        if(model->record(i).value("PARENT_ID").toInt() == 0)
+        if(model->record(i).value("NODE_ID").toInt() == 0)
         {
             QList<QStandardItem*> topRow;
             for(int j = 0; j < 2; j++)
@@ -130,8 +112,6 @@ void FaserDbMainWindow::initializeWindow()
         }
     }
 
-
-
     m_treeView->setModel(m_standardModel);
     m_treeView->expandAll();
     m_treeView->resizeColumnToContents(0);
@@ -139,6 +119,11 @@ void FaserDbMainWindow::initializeWindow()
 
     m_treeView->setSelectionBehavior(QAbstractItemView::SelectRows);
     connect(m_treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &FaserDbMainWindow::selectionChanged);
+    connect(m_listWidget, &QListWidget::currentRowChanged, this, &FaserDbMainWindow::tagRowChanged);
+
+    //Build the list widget
+    buildListWidget();
+
 
     return;
 }
@@ -162,6 +147,13 @@ bool FaserDbMainWindow::isBranch(QString name)
 //testing custom context menu
 void FaserDbMainWindow::contextMenu(const QPoint &point)
 {
+    /*
+    Improvements to this sections code:
+    The end disconnect functions disconnect all
+    Can remove all other disconnects and create one QAction pointer vector
+    That we iterate through at the end to delete
+                                */
+
     //Add branch/leaf functions if selected is a branch
     if(isBranch(m_currentSelected))
     {
@@ -174,43 +166,68 @@ void FaserDbMainWindow::contextMenu(const QPoint &point)
         m_contextMenu->addSeparator();
     }
 
-    //Add create tag action for hvs_node rows only
+    //Add create tag and lock action for hvs_node rows only
     QString current = m_currentSelected;    
     if( !current.endsWith("_DATA") && !current.endsWith("_DATA2TAG"))
     {
-        m_createTag = new QAction("Create Tag", m_contextMenu);
+        if( current == "FASER")
+        {
+            m_createTag = new QAction("Create Root Tag", m_contextMenu);
+            connect(m_createTag, &QAction::triggered, this, &FaserDbMainWindow::createRootTag);
+        }
+        else
+        {
+            m_createTag = new QAction("Create Tag", m_contextMenu);
+            connect(m_createTag, &QAction::triggered, this, &FaserDbMainWindow::createTag );
+        }
+        m_lockTag = new QAction("Lock Tag", m_contextMenu);
         m_contextMenu->addAction(m_createTag);     
-        connect(m_createTag, &QAction::triggered, this, &FaserDbMainWindow::createTag );
+        m_contextMenu->addAction(m_lockTag);
+        //Following is a lambda function, lets us pass lockTag function pointer that has arguments to connect(using default arguments)
+        connect(m_lockTag, &QAction::triggered, this, [this]()
+        {
+            lockTag();
+        });
     }
 
     //If we are looking at root tag, create set root action
-    if( current == QString("FASER"))
+    //Obsolete feature, replaced by left root tag list
+/*    if( current == QString("FASER"))
     {
         m_setRoot = new QAction("Set Root Tag", m_contextMenu);
         m_contextMenu->addAction(m_setRoot);
         connect(m_setRoot, &QAction::triggered, this, &FaserDbMainWindow::setRoot);
-    }
+    }*/
 
-    //Now set current QString to reflect the correspondng data2tag if we are looking at a leaf or data table
+    //Now make QString to reflect the correspondng data2tag if we are looking at a leaf or data table
+    QString tagCurrent;
     if( !isBranch(current) && !current.endsWith("_DATA2TAG"))
     {
+        tagCurrent = current;
         if(current.endsWith("_DATA"))
         {
-            current.replace(QString("_DATA"), QString("_DATA2TAG"));
+            tagCurrent.replace(QString("_DATA"), QString("_DATA2TAG"));
         }
         else
         {
-            current.append("_DATA2TAG");
+            tagCurrent.append("_DATA2TAG");
         }
     }
-    //First build a submenu action for each tag id and set its internal tag id data
-    vector<QAction *> actions;
-    if( current.endsWith("_DATA2TAG") )
+    else if (current.endsWith("_DATA2TAG"))
     {
-        QSqlTableModel model;
-        model.setTable(current);
+        tagCurrent = current;
+    }
+    
+    //Build a submenu action for each tag id and set its internal tag id data
+    vector<QAction *> tagActions;
+    vector<QString> tag_ids;
+
+    //Build list leaf nodes
+    if( !tagCurrent.isNull())
+    {
+        QSqlTableModel model(nullptr, m_database);
+        model.setTable(tagCurrent);
         model.select();
-        vector<QString> tag_ids;
         for(int i = 0; i < model.rowCount(); i++)
         {   
             bool found = false;
@@ -227,13 +244,29 @@ void FaserDbMainWindow::contextMenu(const QPoint &point)
                 tag_ids.push_back(model.record(i).value(0).toString());
             }
         }
-        for(size_t i = 0; i < tag_ids.size(); i++)
+    }
+    //Build list for branch nodes -- currently i dont believe we want this functionallity
+    //Can add back in later, but would need to update setTagFilter's functionality
+/*    else
+    {
+        for(int i = 0; i < m_tagcache.rowCount(); i++)
         {
-            QAction * tempAct = new QAction(tag_ids[i], m_subMenu);
-            actions.push_back(tempAct);
-            tempAct->setData(tag_ids[i]);
-            m_subMenu->addAction(tempAct);
+            if(m_tagcache->record(i).value("CHILDNODE").toString() == current)
+            {
+                tag_ids.push_back(m_tagcache->record(i).value("CHILDTAGID").toString());
+            }
         }
+    }*/
+
+    for(size_t i = 0; i < tag_ids.size(); i++)
+    {
+        QAction * tempAct = new QAction(tag_ids[i], m_subMenu);
+        tagActions.push_back(tempAct);
+        tempAct->setData(tag_ids[i]);
+        m_subMenu->addAction(tempAct);
+    }
+    if( !tagCurrent.isNull())
+    {
         connect(m_subMenu, &QMenu::triggered, this, &FaserDbMainWindow::tagAction);
     }
 
@@ -251,17 +284,18 @@ void FaserDbMainWindow::contextMenu(const QPoint &point)
         delete m_addBranch;
         delete m_addLeaf;
     }
-    if( current == QString("FASER"))
+/*    if( current == QString("FASER"))
     {
         disconnect(m_contextMenu, &QMenu::triggered, this, &FaserDbMainWindow::setRoot);
         delete m_setRoot;
-    }
+    }*/
     if( !current.endsWith("_DATA") && !current.endsWith("_DATA2TAG"))
     {
-        disconnect(m_contextMenu, &QMenu::triggered, this, &FaserDbMainWindow::createTag);
+//        disconnect(m_contextMenu, &QMenu::triggered, this, &FaserDbMainWindow::createTag);
         delete m_createTag;
+        delete m_lockTag;
     }
-    if( m_currentSelected.endsWith("_DATA2TAG") )
+    if( !tagCurrent.isNull() )
     {
         disconnect(m_subMenu, &QMenu::triggered, this, &FaserDbMainWindow::tagAction);
 
@@ -271,10 +305,12 @@ void FaserDbMainWindow::contextMenu(const QPoint &point)
         }
         m_subMenu->clear();*/
     }
-    for(size_t i = 0; i < actions.size(); i++)
+    for(size_t i = 0; i < tagActions.size(); i++)
     {
-        delete actions[i];
+        delete tagActions[i];
     }
+    disconnect(m_contextMenu, 0,0,0);
+    disconnect(m_subMenu, 0,0,0);
     m_subMenu->clear();
 }
 
@@ -338,24 +374,117 @@ void FaserDbMainWindow::createActions()
 
     fileMenu->addSeparator();
 
+    QAction *saveAct = fileMenu->addAction(tr("&Save as text commands"), this, &FaserDbMainWindow::saveFile);
+    saveAct->setShortcuts(QKeySequence::Save);
+    saveAct->setStatusTip(tr("Saves application as a text file containing sql commands to rebuild database"));
+
     QAction *rebuildAct = fileMenu->addAction(tr("&ReBuild"), this, &FaserDbMainWindow::rebuildTree);
     rebuildAct->setStatusTip(tr("Rebuild tree based off of changes"));
 
     QAction *verifyAct = fileMenu->addAction(tr("&Verify Database"), this, &FaserDbMainWindow::verifyDatabase);
     verifyAct->setStatusTip(tr("Verify database adheres to standards"));
 
+    QAction *rootAct = fileMenu->addAction(tr("&Create new root"), this, &FaserDbMainWindow::createRootTag);
+    rootAct->setStatusTip(tr("Creates a new root tag for a new database version"));
+
     QAction *quitAct = fileMenu->addAction(tr("&Quit"), this, &QWidget::close);
     quitAct->setShortcuts(QKeySequence::Quit);
     quitAct->setStatusTip(tr("Quit the application"));
 
-    m_viewMenu = menuBar()->addMenu(tr("&View"));
 
 }
 
+void FaserDbMainWindow::saveFile()
+{
+    bool ok;
+    QString fileName = QInputDialog::getText(this, tr("QInputDialog::getText()"), tr("File name to save to\n(including path if desired)"), QLineEdit::Normal, QString(), &ok);
+    if( !ok )
+    {
+        cout<<"Failed to get file name to save to\n";
+        return;
+    }
+    QFile data(fileName);
+    if (data.open(QFile::WriteOnly)) 
+    {
+        QTextStream outTxt(&data);
+        outTxt << "BEGIN TRANSACTION;\n\n";
+        QSqlQuery query(m_database);
+        query.prepare("SELECT * FROM sqlite_master"); //Get names of tables in database
+        if(query.exec())
+        {
+            while (query.next())
+            {
+                outTxt << "\n";
+                //Gets name of table to do new query of it
+                QString queryText = QString("SELECT * FROM %1").arg(query.record().value(1).toString());
+                QSqlQuery subQuery(m_database);
+                subQuery.prepare(queryText);
+                bool firstLine=true;
+                if(subQuery.exec())
+                {
+                    outTxt << "DROP TABLE IF EXISTS \""<<query.record().value(1).toString()<<"\";\nCREATE TABLE IF NOT EXISTS \""<<query.record().value(1).toString()<<"\" (\n";
+                    while( subQuery.next())
+                    {
+                        const QSqlRecord recrd= subQuery.record();
+                        //Creates table query
+                        if(firstLine)
+                        {
+                            QSqlQuery typeQuery(m_database);
+                            QString typeString = QString("PRAGMA table_info(%1)").arg(query.record().value(1).toString());
+                            typeQuery.prepare(typeString);
+                            typeQuery.exec();
+                            bool prevAdded = false;
+                            while( typeQuery.next())
+                            {
+                                if(prevAdded)
+                                {
+                                    outTxt << ",\n";
+                                }
+                                prevAdded = true;
+                                QString name = typeQuery.value("name").toString();
+                                QString type = typeQuery.value("type").toString();
+                                outTxt << "\t";
+                                outTxt << "\""<< name <<"\"\t"<< type; //Headers
+                            }
+                            outTxt << "\n);\n\n";
+                        }
+                        firstLine=false;
+                        outTxt << "INSERT INTO \"" << query.record().value(1).toString()<< "\" VALUES (";
+                        for(int i=0;i<recrd.count();++i)
+                        {
+                            if( i != 0)
+                            {
+                                outTxt << ", ";
+                            }
+                            if(recrd.value(i).isNull())
+                            {
+                                outTxt << "NULL";
+                            }
+                            else
+                            {
+                                if(recrd.value(i).userType() == QMetaType::QString )
+                                {
+                                    outTxt << "'";
+                                }
+                                outTxt << recrd.value(i).toString();
+                                if(recrd.value(i).userType() == QMetaType::QString )
+                                {
+                                    outTxt << "'";
+                                }
+                            }   
+                        }
+                        outTxt << ");\n";
+                    }
+                }
+            }
+        outTxt << "COMMIT;";
+        }
+	data.close();
+} 
+}
+
 QString FaserDbMainWindow::selectedRowName()
 {
-//    int row = m_treeView->currentIndex().row();
-//    return m_treeView->model()->data( m_treeView->model()->index(row, 1)).toString();
     return m_currentSelected;
 }
 
@@ -366,11 +495,10 @@ void FaserDbMainWindow::rebuildTree()
 
     m_hvsNodeTableModel->select();
     QSqlTableModel *model = m_hvsNodeTableModel;
-//    QSqlTableModel *model = m_secondWindow->tablePointer();
     
-    for(int i = 1; i < model->rowCount(); i++)
+    for(int i = 0; i < model->rowCount(); i++)
     {
-        if(model->record(i).value("PARENT_ID").toInt() == 0)
+        if(model->record(i).value("NODE_ID").toInt() == 0)
         {
             QList<QStandardItem*> topRow;
             for(int j = 0; j < 2; j++)
@@ -383,6 +511,7 @@ void FaserDbMainWindow::rebuildTree()
         }
     }
     
+
     m_treeView->expandAll();
     m_treeView->resizeColumnToContents(0);
     m_treeView->resizeColumnToContents(1);
@@ -399,7 +528,8 @@ bool FaserDbMainWindow::verifyDatabase()
     bool ltag2ltagExists = false;
     bool tag2nodeExists = false;
     bool tagcacheExists = false;
-    vector<QString> masterTables;
+    vector<string> masterTables;
+    //Build a list of all tables in the database
     for(int i = 0; i < masterTable.rowCount(); i++)
     {
         QString tableName = masterTable.record(i).value(1).toString();
@@ -409,9 +539,10 @@ bool FaserDbMainWindow::verifyDatabase()
         tagcacheExists = nodeExists || (tableName.toStdString() == "HVS_tagcache") ? true : false;
         if(masterTable.record(i).value("type").toString() == "table")
         {
-            masterTables.push_back(tableName);        
+            masterTables.push_back(tableName.toStdString());        
         }
     }
+    //Check that main tables exist
     if( !(ltag2ltagExists && nodeExists && tag2nodeExists && tagcacheExists))
     {
         if(!nodeExists)
@@ -509,7 +640,154 @@ bool FaserDbMainWindow::verifyDatabase()
     }
 
     //Now we need to verify that HVS_NODE is built properly
+    //Ensure a _DATA and _DATA2TAG table for each leaf
+    //Check no hanging children or extraneous tables
+
+    //First check branch/leaf structure in hvs_node
+    vector<int> parent_ids;
+    for(int i = 0; i < hvsNodeTable.rowCount(); i++)
+    {
+        if( hvsNodeTable.record(i).value("BRANCH_FLAG").toString() == "1")
+        {
+            parent_ids.push_back(hvsNodeTable.record(i).value("NODE_ID").toString().toInt());
+        }
+    }
+    for(int i = 0; i < hvsNodeTable.rowCount(); i++)
+    {
+        QString nodeName = hvsNodeTable.record(i).value("NODE_NAME").toString();
+        QString parentId = hvsNodeTable.record(i).value("PARENT_ID").toString();
+        QString nodeId = hvsNodeTable.record(i).value("NODE_ID").toString();
+        if( nodeId != "0" && std::find(parent_ids.begin(), parent_ids.end(), parentId.toInt()) == parent_ids.end())
+        {
+            string err = "Parent of ";
+            err += hvsNodeTable.record(i).value("NODE_NAME").toString().toStdString();
+            err += "is not a branch";
+            m_errors.push_back(err);
+        }
+
+        //Now do different logic on branch or leaves
+        //Branches first, ensure there are no _DATA or _DATA2TAG tables for it
+        if(hvsNodeTable.record(i).value("BRANCH_FLAG").toString() == "1")
+        {
+            string check_data = hvsNodeTable.record(i).value("NODE_NAME").toString().toStdString();
+            check_data += "_DATA";
+            transform(check_data.begin(), check_data.end(), check_data.begin(), ::toupper);
+            string check_data2tag = hvsNodeTable.record(i).value("NODE_NAME").toString().toStdString();
+            check_data2tag += "_DATA2TAG";
+            transform(check_data2tag.begin(), check_data2tag.end(), check_data2tag.begin(), ::toupper);
+            if( std::find(masterTables.begin(), masterTables.end(), check_data) != masterTables.end())
+            {
+                string err = "Found _DATA table for branch node in HVS_NODE : ";
+                err += check_data;
+                m_errors.push_back(err);
+            }
+            if( std::find(masterTables.begin(), masterTables.end(), check_data2tag) != masterTables.end())
+            {
+                string err = "Found _DATA2TAG table for branch node in HVS_NODE : ";
+                err += check_data2tag;
+                m_errors.push_back(err);
+            }
+        }   
+        else //Checking leaf
+        {
+            string check_data = hvsNodeTable.record(i).value("NODE_NAME").toString().toStdString();
+            check_data += "_DATA";
+            transform(check_data.begin(), check_data.end(), check_data.begin(), ::toupper);
+            string check_data2tag = hvsNodeTable.record(i).value("NODE_NAME").toString().toStdString();
+            check_data2tag += "_DATA2TAG";
+            transform(check_data2tag.begin(), check_data2tag.end(), check_data2tag.begin(), ::toupper);
+
+            vector<int> leafDataIds;
+            vector<int> leafTagIds;
+
+            auto it = std::find(masterTables.begin(), masterTables.end(), check_data);
+            if( it != masterTables.end())
+            {
+                //Remove the found table from master list vector if found
+                masterTables.erase( it);
+                //Also build list of data id's
+                QSqlTableModel leaf;
+                leaf.setTable(QString::fromStdString(check_data));
+                leaf.select();
+                for(int i = 0; i < leaf.rowCount(); i++)
+                {
+                    int dataid = leaf.record(i).value(0).toString().toInt();
+                    if( std::find(leafDataIds.begin(), leafDataIds.end(), dataid) == leafDataIds.end())
+                    {
+                        leafDataIds.push_back(dataid);
+                    }
+                    else
+                    {
+                        string err = "Repeated data tag in ";
+                        err += check_data;
+                        err += " of ";
+                        err += std::to_string(dataid);
+                        m_errors.push_back(err);
+                    }
+                }
+            }
+            else
+            {
+                string err = "Missing _DATA table ";
+                err += check_data;
+                m_errors.push_back(err);
+            }
+
+            it = std::find(masterTables.begin(), masterTables.end(), check_data2tag);
+            if( it != masterTables.end())
+            {
+                //Erase from list of master tables
+                masterTables.erase( it);
+                //Also check that ever data id in _data has a tag
+                //And that every tag is associated with this table in tag2node
+                QSqlTableModel leaf;
+                leaf.setTable(QString::fromStdString(check_data2tag));
+                leaf.select();
+
+                for(int i = 0; i < leaf.rowCount(); i++)
+                {
+                    int data = leaf.record(i).value(1).toString().toInt();
+                    int tag = leaf.record(i).value(0).toString().toInt();
+                    if(std::find(leafDataIds.begin(), leafDataIds.end(), data) == leafDataIds.end())
+                    {
+                        string err = "No reference to data id ";
+                        err += std::to_string(data);
+                        err += " in ";
+                        err += check_data2tag;
+                        m_errors.push_back(err);
+                    }
+                    if(std::find(leafTagIds.begin(), leafTagIds.end(), tag) != leafTagIds.end())
+                    {
+                        leafTagIds.push_back(tag);
+                    }
+                }
+
+                for(size_t i = 0; i < leafTagIds.size(); i++)
+                {
+                    if( nodeId != findAssociated( &hvsTag2NodeTable, QString("TAG_ID"), QString(leafTagIds[i]), QString("NODE_ID")))
+                    {
+                        string err = "Tag of ";
+                        err += std::to_string(leafTagIds[i]);
+                        err += "not associated with the node ";
+                        err += nodeName.toStdString();
+                        m_errors.push_back(err);
+                    }
+                }
+
+            }
+            else
+            {
+                string err = "Missing _DATA2TAG table ";
+                err += check_data2tag;
+                m_errors.push_back(err);
+            }
+            
+            
+        }
+         
 
+    }
+    
 
 
     if(m_errors.empty())
@@ -518,6 +796,8 @@ bool FaserDbMainWindow::verifyDatabase()
     }
     else
     {
+        string err = "Errors were found in database verification - check terminal for log";
+        errorMessage(err);
         printErrors();
         return false;
     }
@@ -548,10 +828,42 @@ void FaserDbMainWindow::createStatusBar()
 void FaserDbMainWindow::buildChildren( QList<QStandardItem*> *PRow, QString parent_id)
 {   
     QSqlTableModel *model = m_hvsNodeTableModel;
+    
+    QSqlTableModel tagcache;
+    tagcache.setTable("HVS_TAGCACHE");
+    tagcache.select();
 //    QSqlTableModel *model = m_secondWindow->tablePointer();
-    for(int i = 1; i < model->rowCount(); i++)
+
+    if(!m_rootDisplayTag.isNull())
+    {
+        for(int j = 0; j < m_tagcache->rowCount(); j++)
+        {
+            if(m_tagcache->record(j).value("ROOTTAG").toString() == m_rootDisplayTag
+                && m_tagcache->record(j).value("CHILDNODE").toString() == PRow->at(1)->data(Qt::DisplayRole).toString())
+            {
+                if( isLocked(m_tagcache->record(j).value("CHILDTAGID").toString()))
+                {
+                    PRow->at(0)->setBackground(Qt::red);
+                }
+                else
+                {
+                    PRow->at(0)->setBackground(Qt::green);
+                }
+                break;
+            }
+        }
+    }
+    else
+    {
+        PRow->at(0)->setBackground(QColor(Qt::white));
+    }
+
+    for(int i = 0; i < model->rowCount(); i++)
     {
-        if(model->record(i).value("PARENT_ID").toString() == parent_id)
+        //Add new row if it is a child and part of our current root tag system if we have one
+        if(model->record(i).value("PARENT_ID").toString() == parent_id && model->record(i).value("NODE_ID").toInt() != 0
+            && (m_rootDisplayTag.isNull() || 
+            findAssociatedList( &tagcache, QString("ROOTTAG"), m_rootDisplayTag, QString("CHILDNODE")).contains(model->record(i).value("NODE_NAME").toString())))
         {  
             QList<QStandardItem*> *newRow = new QList<QStandardItem*>;
             for(int j = 0; j < 2; j++)
@@ -575,9 +887,35 @@ void FaserDbMainWindow::buildChildren( QList<QStandardItem*> *PRow, QString pare
 
                 newRow->first()->appendRow(dataRow);
                 newRow->first()->appendRow(data2tagRow);
-                
+            if(!m_rootDisplayTag.isNull())
+                {
+                    QSqlTableModel tagcache;
+                    tagcache.setTable("HVS_TAGCACHE");
+                    tagcache.select();
+                    for(int j = 0; j < tagcache.rowCount(); j++)
+                    {
+                        if(tagcache.record(j).value("ROOTTAG").toString() == m_rootDisplayTag
+                            && tagcache.record(j).value("CHILDNODE").toString() == newRow->at(1)->data(Qt::DisplayRole).toString())
+                        {
+                            if( isLocked(tagcache.record(j).value("CHILDTAGID").toString()))
+                            {
+                                newRow->at(0)->setBackground(Qt::red);
+                            }
+                            else
+                            {
+                                newRow->at(0)->setBackground(Qt::green);
+                            }
+                            break;
+                        }
+                    }
+                }
+                else
+                {
+                    newRow->at(0)->setBackground(Qt::white);
+                }              
             }
 
+            
             PRow->first()->appendRow(*newRow);
         }
     }
@@ -615,9 +953,36 @@ void FaserDbMainWindow::addBranch()
         return;
     }
 
+    //Can't add branch to a locked table
+    if( !m_rootDisplayTag.isNull())
+    {
+        for(int i = 0; i < m_tagcache->rowCount(); i++)
+        {
+            if(m_tagcache->record(i).value("ROOTTAG").toString() == m_rootDisplayTag
+                && m_tagcache->record(i).value("CHILDNODE").toString() == selectedRowName())
+            {
+                if(isLocked(m_tagcache->record(i).value("CHILDTAGID").toString()))
+                {
+                    errorMessage("Cannot add branch to a locked node");
+                    return;
+                }
+                else
+                {
+                    break;
+                }
+            }
+        }
+    }
+
     //Get name of table we are creating
     bool ok;
-    QString text = QInputDialog::getText(this, tr("QInputDialog::getText()"), tr("New Table Name"), QLineEdit::Normal, QDir::home().dirName(),&ok);
+    QString text = QInputDialog::getText(this, tr("QInputDialog::getText()"), tr("New Table Name"), QLineEdit::Normal, selectedRowName(),&ok);
+    if(!findAssociated(m_hvsNodeTableModel, QString("NODE_NAME"), text, QString("NODE_ID")).isNull())
+    {
+        errorMessage("Cannot create new branch with same name as existing branch");
+        return;
+    }
+
 
     if( !ok)
     {   
@@ -642,24 +1007,26 @@ void FaserDbMainWindow::addBranch()
     int row = m_hvsNodeTableModel->rowCount();
 
     //Need to add new branch into related tag tables with a new tag
-    QSqlTableModel tag2node;
-    QSqlTableModel ltag2ltag;
-    QSqlTableModel tagcache;
+/*    QSqlTableModel tag2node(nullptr, m_database);
+    QSqlTableModel ltag2ltag(nullptr, m_database);
+    QSqlTableModel tagcache(nullptr, m_database);
     tag2node.setTable("HVS_TAG2NODE");
     ltag2ltag.setTable("HVS_LTAG2LTAG");
     tagcache.setTable("HVS_TAGCACHE");
     tag2node.select();
     ltag2ltag.select();
-    tagcache.select();
+    tagcache.select();*/
 
     QString currentNodeName = selectedRowName();
     QString currentNodeId = findAssociated(m_hvsNodeTableModel, QString("NODE_NAME"), currentNodeName, QString("NODE_ID"));
     
+    QString parentTagName;
     QString parentTag;
     //Need to get unlocked parent tag to make new node under
+    //Get from user if root tag isn't set
     if(m_rootDisplayTag.isNull())
     {
-        QStringList parentTags = findAssociatedList(&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;
+
+
+}
+
+
+
 
diff --git a/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserDbMainWindow.h b/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserDbMainWindow.h
index 3c15d9fee2912c747b093ba385f64d5519c254f3..d8dd30381a90e0aefee9f0880aad359610ad4a88 100644
--- a/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserDbMainWindow.h
+++ b/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserDbMainWindow.h
@@ -7,6 +7,9 @@
 #include <QDialog>
 #include <QTableView>
 #include <QtSql>
+#include <QListWidget>
+//#include "FaserDbSecondWindow.h"
+//#include "FaserDbRelTableModel.h"
 
 
 // #include <QtGui/QWidget>
@@ -22,11 +25,14 @@ QT_END_NAMESPACE
 
 
 class FaserDbSecondWindow;
+class FaserDbRelTableModel;
+class FaserGeoEditorApp;
 
 class FaserDbMainWindow : public QMainWindow
 {
     Q_OBJECT
 private:
+    FaserGeoEditorApp *m_editorApp;
     QTreeView *m_treeView;
     QStandardItemModel *m_standardModel;
     QSqlDatabase m_database;
@@ -37,17 +43,16 @@ private:
     QDialogButtonBox *m_buttonBox;*/
     FaserDbSecondWindow *m_secondWindow;
     QSqlTableModel *m_hvsNodeTableModel;
-    QMenu *m_viewMenu;
     QMenu *m_contextMenu;
     QMenu *m_subMenu;
     QAction *m_addBranch;
     QAction *m_addLeaf;
     QAction *m_createTag;
-    QAction *m_testTag1;
-    QAction *m_testTag2;
-    QAction *m_setRoot;
+//    QAction *m_setRoot;
+    QAction *m_lockTag;
     QString m_currentSelected;
     vector<string> m_errors;
+    QListWidget *m_listWidget;
 
     void printErrors();
     void createActions();
@@ -64,26 +69,36 @@ private:
 //    string obtainNamePopup();
 
 public:
+    QSqlTableModel *m_tag2node;
+    QSqlTableModel *m_tagcache;
+    QSqlTableModel *m_ltag2ltag;
 
     QString m_rootDisplayTag;
     void initializeWindow();
-    FaserDbMainWindow(QWidget *parent = nullptr);
+    FaserDbMainWindow(QWidget *parent = nullptr, FaserGeoEditorApp *parentApp = nullptr);
     QList<QStandardItem*> prepareRow(  const QString& name1, const QString& name2, const QString& name3, const QString& name4, const QString& name5);
     void buildChildren( QList<QStandardItem*> *Row, QString parent_id);
     void setDatabase( QSqlDatabase *db);
 //    void submit();
     QSqlDatabase returnDatabase();
     void rebuildTree();
+    void saveFile();
+    void buildListWidget();
     bool verifyDatabase();
     QString selectedRowName();
     void selectionChanged(const QItemSelection&, const QItemSelection&);
+    void tagRowChanged(int currentRow);
     bool isLocked(QString tagId);
     QStringList findAssociatedList(QSqlTableModel *table, QString known, QString kvalue, QString search);
     QString findAssociated(QSqlTableModel *table, QString known, QString kvalue, QString search);
     QString createTag();
+    QString createRootTag();
+    void lockTag(QString toLock = QString());
 
     void errorMessage(string message);
 
+    bool submitChanges(QSqlTableModel *table);
+
 
 
     // virtual ~FaserDbMainWindow();
@@ -99,11 +114,14 @@ public:
     FaserDbPopup(FaserDbMainWindow *window_parent, QWidget *parent = nullptr);
 };*/
 
+
 class FaserDbSecondWindow : public QWidget
 {
     Q_OBJECT
 private:
-    QSqlRelationalTableModel *m_tableModel;
+//    QSqlRelationalTableModel *m_tableModel;
+    FaserDbRelTableModel *m_tableModel;
+
 //    QSqlTableModel *m_tableModel; previously used, replaced with relational
     QPushButton *m_submitButton;
     QPushButton *m_revertButton;
@@ -113,14 +131,17 @@ private:
     QPushButton *m_removeColumn;
     QPushButton *m_removeRow;
     QDialogButtonBox *m_buttonBox;
-    FaserDbMainWindow *m_parentWindow;
-    QTableView *m_tableView;
 
     QString m_rootTag;
 
 
 public:
+    QTableView *m_tableView;
+    QSqlTableModel *m_tagTable;
+    QSqlTableModel *m_sqlTableModel;
+    FaserDbMainWindow *m_parentWindow;
     FaserDbSecondWindow( FaserDbMainWindow *window_parent, QWidget *parent = nullptr);
+    ~FaserDbSecondWindow();
     void submit();
 //    QSqlTableModel* tablePointer();
     void addRow();
@@ -132,18 +153,24 @@ public:
     void setTagFilter(QString tagFilter);
 
     void click_cell(int row, int column);
+    vector<bool> m_isLocked;
 
 //    Qt::ItemFlags flags(const QModelIndex &index) const;
 
 };
 
-class testtest : public QSqlRelationalTableModel
-{
 
+class FaserDbRelTableModel : public QSqlRelationalTableModel
+{
+    private:
+    FaserDbSecondWindow *m_secondWindow;
     public:
+    FaserDbRelTableModel(QObject *parent, QSqlDatabase db, FaserDbSecondWindow *secondWin);
+    QVariant data(const QModelIndex &idx, int role) const;
     Qt::ItemFlags flags(const QModelIndex &index) const;
 };
 
+
 //Qt::ItemFlags QAbstractItemModel::flags(const QModelIndex &index) const;
 
 // #endif
\ No newline at end of file
diff --git a/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserGeoEditorApp.cxx b/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserGeoEditorApp.cxx
index e202c0def212230606d2f397ebebcf3871f7c757..5a199a4d87fcfb020963573d5c864ec063e84a78 100644
--- a/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserGeoEditorApp.cxx
+++ b/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserGeoEditorApp.cxx
@@ -1,17 +1,54 @@
 #include <iostream>
+#include <QFile>
 #include "FaserGeoEditorApp.h"
 
-FaserGeoEditorApp::FaserGeoEditorApp(int& argc, char** argv) 
-: m_application(argc, argv), m_database(QSqlDatabase::addDatabase("QSQLITE")), m_mainWindow()
+FaserGeoEditorApp::FaserGeoEditorApp(int& argc, char** argv, string type) 
+: m_application(argc, argv), m_database(QSqlDatabase::addDatabase("QSQLITE")), m_mainWindow(nullptr, this)
 { 
+    //Need to separate cases of opening a text and binary file
+/*    if(type = "t")
+    {
+        //do something here
+    }
+    else
+    {
+        m_application = new QApplication(argc, argv);
+        m_database = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE"));
+        m_mainWindow = new FaserDbMainWindow(nullptr, this);
+    }*/
+    
+
 // db file name should be first argument after command name; retrieve it
     auto arguments = m_application.arguments();
     auto dbName = arguments.at(1);
     std::cout << "Database name: " << dbName.toLocal8Bit().constData() << std::endl;
 
-    m_database.setDatabaseName(dbName);
-    bool ok = m_database.open();
+    bool ok;
+    cout<<"type:"<<type<<endl;
+    if( strcmp(type.c_str(), "b") == 0)
+    {
+        m_database.setDatabaseName(dbName);
+        ok = m_database.open();
+    }
+    else
+    {
+        cout<<"Binary file will initially be saved to current directory as GeoEditorSqlite\n";
+        m_database.setDatabaseName("GeoEditorSqlite");
+        ok = m_database.open();
+    
+        if(ExecuteSqlScriptFile( m_database, dbName) == 0)
+        {
+            cout<<"Exiting...\n";
+            return;
+        }
+    }
+    
     std::cout << "Database open status: " << ok << std::endl;
+    if(!ok)
+    {
+        cout<<"Failed to open database, exiting...\n";
+        return;
+    }
     m_mainWindow.setDatabase(&m_database);
     m_mainWindow.initializeWindow();
 
@@ -23,4 +60,33 @@ int FaserGeoEditorApp::exec()
 {
     m_mainWindow.show();
     return m_application.exec();
-}
\ No newline at end of file
+}
+
+int FaserGeoEditorApp::ExecuteSqlScriptFile(QSqlDatabase & db, const QString & fileName)
+{
+    cout<<"executing\n";
+    QFile file(fileName);
+    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+    {
+        cout<<"Error opening file to save to\n";
+        return  0;
+    }
+
+    QTextStream in(&file);
+    QString sql = in.readAll();
+    QStringList sqlStatements = sql.split(';', QString::SkipEmptyParts);
+    int successCount = 0;
+ 
+    foreach(const QString& statement, sqlStatements)
+    {
+        if (statement.trimmed() != "")
+        {
+            QSqlQuery query(db);
+            if (query.exec(statement))
+                successCount++;
+            else
+                std::cout << "Failed:" << statement.toStdString() << "\nReason:" << query.lastError().text().toStdString()<<endl;
+        }
+    }
+    return successCount;
+}
diff --git a/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserGeoEditorApp.h b/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserGeoEditorApp.h
index 77df7d15737b936e9b3051923a1af648bfc2cd08..f9dbe459dc2063eca158e33478661e2a709c5798 100644
--- a/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserGeoEditorApp.h
+++ b/DetectorDescription/GeoModel/FaserGeoEditor/src/FaserGeoEditorApp.h
@@ -9,9 +9,13 @@
 class FaserGeoEditorApp
 {
     public:
-        FaserGeoEditorApp(int& argc, char** argv);
+        FaserGeoEditorApp(int& argc, char** argv, string type);
+
+//        string textToBinary(string fileName);
+//        string binaryToText(string fileName);
 
         int exec();
+        int ExecuteSqlScriptFile(QSqlDatabase & db, const QString & fileName);
         QSqlDatabase& getDatabase() { return m_database; }
     private:
         QApplication m_application;
diff --git a/DetectorDescription/GeoModel/FaserGeoEditor/src/main.cxx b/DetectorDescription/GeoModel/FaserGeoEditor/src/main.cxx
index d9ee9d7ae80a5c16b6d7d281966205a140aa83d0..fbb224a7f6d423fcd22e81fe4215e055c2a0fac5 100644
--- a/DetectorDescription/GeoModel/FaserGeoEditor/src/main.cxx
+++ b/DetectorDescription/GeoModel/FaserGeoEditor/src/main.cxx
@@ -1,14 +1,48 @@
 // main.cpp
 #include "FaserGeoEditorApp.h"
+#include <iostream>
 // #include <QTableView>
 // #include <QStringList>
 // #include <QSqlDatabase>
 // #include <iostream>
 // #include "mymodel.h"
+//#include <string.h>
+//#include <sqlite3.h>
+//#include <fstream>
+
+//string textToBinary(string textFileName, string binFileName = std::string(""));
 
 int main(int argc, char *argv[])
 {
-    FaserGeoEditorApp a(argc, argv);
+    if(argc != 3)
+    {
+        std::cout<<"Error: Require two command line inputs only, first path to application, second path to database, third to indicate binary vs text file\n";
+        std::cout<<"Example: bin/FaserGeoEditor data/geomDB_sqlite t\n";
+        return 0;
+    }
+    string type;
+    string fileName;
+    if( strcmp(argv[2], "t") || strcmp(argv[2], "T"))
+    {
+        type = "t";
+//        fileName = textToBinary(argv[1]);
+    }
+    else if( strcmp(argv[2], "b") || strcmp(argv[2], "B"))
+    {
+        type = "b";
+    }
+    else    
+    {
+        std::cout<<argv[2]<<endl;
+        std::cout<<"Error: third argument incorrectly indicating if file is text or binary; only use t or b to indicate\n";
+        return 0;
+    }
+    char *reducedArgv[2];
+    reducedArgv[0] = argv[0];
+    reducedArgv[1] = argv[1];
+    argc = 2;
+    
+    FaserGeoEditorApp a(argc, reducedArgv, type);
     // QApplication a(argc, argv);
 
     // QTableView tableView;
@@ -19,3 +53,54 @@ int main(int argc, char *argv[])
     // w.show();
     return a.exec();
 }
+/*
+string textToBinary(string textFileName, string binFileName)
+{
+	int rc;
+	char *zErrMsg;
+    sqlite3 *database;
+
+	string sqlFileName = textFileName;
+    sqlFileName.append("sql");
+	string sqlToRun;
+	string singlestring;
+
+	rc = sqlite3_open((sqlFileName).c_str(), &database);
+	if(rc)
+	{
+		cout<<"Failed to open file\n\n";
+        return nullptr;
+	}
+	else
+	{
+		cout<<"File opened\n\n";
+	}
+	
+	cout<<"Enter name of sql file:";
+	cin>>textFileName;
+	ifstream openedFile;
+	openedFile.open(textFileName.c_str());
+
+	while(!openedFile.eof())
+	{
+		sqlToRun.clear();
+		singlestring = "a";
+		while(!openedFile.eof() && *singlestring.rbegin() != ';')
+		{
+			singlestring.clear();
+			getline(openedFile, singlestring);
+			sqlToRun = sqlToRun + singlestring;
+		}
+		rc = sqlite3_exec(database, sqlToRun.c_str(), NULL, 0, &zErrMsg);
+		if( rc!=SQLITE_OK)
+		{
+			cout<<zErrMsg;
+			cout<<"\n";
+			sqlite3_free(zErrMsg);
+		}
+		
+	}
+	cout<<"SQL commands run successfully!\n\n";
+
+	return sqlFileName;
+}*/