#include #include #include #include #include "MainWindow.h" #include "NewDialog.h" #include "Database.h" #include "object/enum.objtypes.h" #include "object/AnalogInputView.h" #include "object/AnalogOutputView.h" #include "object/AnalogValueView.h" #include "object/BinaryInputView.h" #include "object/BinaryOutputView.h" #include "object/BinaryValueView.h" #include "object/MultInputView.h" #include "object/DeviceView.h" using namespace std; int MainWindow::AskToSave() { QMessageBox::StandardButton ret = QMessageBox::warning(this, QObject::tr("Hey!"), QObject::tr("Save database?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); if(ret == QMessageBox::Save) save(); return (ret != QMessageBox::Cancel); } // Menu actions void MainWindow::open() { if(bModified && !AskToSave()) return; QString fileName = QFileDialog::getOpenFileName(this, tr("Load Database"), NULL, tr("BACnet Databases (*.bdb *sqlite)")); QString tmpName = fileName + ".working"; Database *tryDB = NULL; int i = 0; bool copySuccess; if(fileName != NULL) { if(bDBLoaded) dbh->close(); copySuccess = QFile::copy(fileName, tmpName); while(!copySuccess) { tmpName = fileName + ".working." + QString::number(i++); copySuccess = QFile::copy(fileName, tmpName); } tryDB = new Database(); tryDB->open(tmpName); if(!tryDB->Opened()) QMessageBox::about(NULL, tr("Error"), tr("Failed to open database.")); else { if(bDBLoaded) dbh->close(); dbh = tryDB; if(tempFilename != "") QFile::remove(tempFilename); saveFilename = fileName; tempFilename = tmpName; bDBLoaded = true; loadData(); } } } void MainWindow::save() { QString fileName; if(saveFilename == NULL) saveAs(); QFile::remove(saveFilename); QFile::copy(tempFilename, saveFilename); bModified = false; } void MainWindow::saveAs() { saveFilename = QFileDialog::getSaveFileName(this, tr("Load Database"), NULL, tr("BACnet Databases(*.bdb *sqlite)")); } // Event Handlers void MainWindow::closeEvent(QCloseEvent *event) { if(bModified && !AskToSave()) event->ignore(); else event->accept(); } void MainWindow::keyPressEvent(QKeyEvent *event) { if(event->key() == Qt::Key_Delete) { if(objData != nothingSelected) { // Delete from database QSqlQuery query(*dbh); query.prepare("DELETE FROM object WHERE id = :id"); query.bindValue(":id", objData->ObjId); query.exec(); query.prepare("DELETE FROM property WHERE object = :id"); query.bindValue(":id", objData->ObjId); query.exec(); // Remove from object list delete objList->takeItem(objList->currentRow()); // I think when the item is removed, it will trigger loadItem() on the new selection. bModified = true; } } } void MainWindow::createNew() { // Return early if user cancels if(bModified && !AskToSave()) return; Database *tryDB; QFile::remove(".working"); tryDB = new Database(); tryDB->open(".working"); if(!tryDB->Opened()) QMessageBox::about(NULL, "Error", "Failed to create new database."); else { if(bDBLoaded) dbh->close(); dbh = tryDB; dbh->exec("CREATE TABLE object (id INTEGER PRIMARY KEY, obj_type INTEGER, obj_num INTEGER, obj_text STRING)"); dbh->exec("CREATE TABLE property (id INTEGER PRIMARY KEY, object INTEGER, prop_id INTEGER, prop_name STRING, " "prop_type ENUM, prop_size INTEGER, prop_val BLOB, readable BOOL, writable BOOL)"); dbh->exec("INSERT INTO object VALUES (0, 8, 1, \"New Device\")"); saveFilename = ""; if(tempFilename != "") QFile::remove(tempFilename); tempFilename = ".working"; bDBLoaded = true; } loadData(); } void MainWindow::newObj() { CreateNewDialog *d = new CreateNewDialog(workspace, NumObjects); int ret = d->exec(); if(ret == QDialog::Accepted) { QSqlQuery query(*dbh); query.prepare("INSERT INTO object (obj_type, obj_num, obj_text) VALUES (:type, :num, :name)"); query.bindValue(":type", d->ObjType()); query.bindValue(":num", d->ObjNum()); query.bindValue(":name", d->ObjName()); query.exec(); query.exec("SELECT LAST_INSERT_ROWID()"); query.next(); QListWidgetItem *item = new QListWidgetItem(d->ObjName(), objList); item->setData(Qt::UserRole, query.value(0)); objList->setCurrentItem(item); loadItem(item); ++NumObjects[d->ObjType()]; bModified = true; } delete d; } void MainWindow::resetObj() { if(objData != nothingSelected) loadItem(objList->currentItem()); } void MainWindow::saveObj() { if(objData != nothingSelected) { QListWidgetItem *item = objList->currentItem(); objData->DBSave(); item->setText(objData->ObjName); } bModified = true; } // Database accessors void MainWindow::loadData() { QSqlQuery query("SELECT id, obj_type, obj_text FROM object ORDER BY obj_type, obj_num", *dbh); QSqlRecord rec = query.record(); int text_idx = rec.indexOf("obj_text"); int type_idx = rec.indexOf("obj_type"); if(objData == nothingSelected) objData->hide(); else delete objData; objData = nothingSelected; objData->show(); layout->addWidget(objData, 0, 1); objList->clear(); while(query.next()) { QListWidgetItem *item = new QListWidgetItem(query.value(text_idx).toString(), objList); item->setData(Qt::UserRole, query.value(0)); if(query.value(type_idx).toInt() == OBJ_DEVICE) { item->setForeground(QBrush(QColor(172,30,30))); objList->setCurrentItem(item); loadItem(item); } ++NumObjects[query.value(type_idx).toInt()]; } objList->show(); } void MainWindow::loadItem(QListWidgetItem *item) { if(item != NULL) { QSqlQuery query("SELECT id, obj_type, obj_num, obj_text FROM object WHERE id = " + item->data(Qt::UserRole).toString(), *dbh); query.next(); int id = query.value(0).toInt(); int type = query.value(1).toInt(); int num = query.value(2).toInt(); QString name = query.value(3).toString(); if(objData == nothingSelected) objData->hide(); else delete objData; switch(type) { case OBJ_DEVICE: objData = new DeviceView(workspace, dbh, id, name, type, num); layout->addWidget(objData, 0, 1); break; case OBJ_AN_INPUT: objData = new AnalogInputView(workspace, dbh, id, name, type, num); layout->addWidget(objData, 0, 1); break; case OBJ_AN_OUTPUT: objData = new AnalogOutputView(workspace, dbh, id, name, type, num); layout->addWidget(objData, 0, 1); break; case OBJ_AN_VAR: objData = new AnalogValueView(workspace, dbh, id, name, type, num); layout->addWidget(objData, 0, 1); break; case OBJ_BI_INPUT: objData = new BinaryInputView(workspace, dbh, id, name, type, num); layout->addWidget(objData, 0, 1); break; case OBJ_BI_OUTPUT: objData = new BinaryOutputView(workspace, dbh, id, name, type, num); layout->addWidget(objData, 0, 1); break; case OBJ_BI_VAR: objData = new BinaryValueView(workspace, dbh, id, name, type, num); layout->addWidget(objData, 0, 1); break; case OBJ_MS_INPUT: objData = new MultInputView(workspace, dbh, id, name, type, num); layout->addWidget(objData, 0, 1); break; default: objData = nothingSelected; objData->show(); break; } } else if(objData != nothingSelected) { delete objData; objData = nothingSelected; objData->show(); } } // Draw window void MainWindow::drawWindow() { btNew = new QPushButton(tr("New Object..."), workspace); btApply = new QPushButton(tr("Apply"), workspace); btReset = new QPushButton(tr("Reset"), workspace); connect(btNew, SIGNAL(clicked()), this, SLOT(newObj())); connect(btReset, SIGNAL(clicked()), this, SLOT(resetObj())); connect(btApply, SIGNAL(clicked()), this, SLOT(saveObj())); QHBoxLayout *saveBtns = new QHBoxLayout(); layout = new QGridLayout(); layout->setObjectName("main layout"); nothingSelected = new ObjectView(workspace); objData = nothingSelected; objList = new QListWidget(workspace); objList->setViewMode(QListWidget::ListMode); connect(objList, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this, SLOT(loadItem(QListWidgetItem *))); saveBtns->addStretch(3); saveBtns->addWidget(btApply, 1); saveBtns->addWidget(btReset, 1); layout->addWidget(objList, 0, 0); layout->addWidget(btNew, 1, 0); layout->addWidget(objData, 0, 1); layout->addLayout(saveBtns, 1, 1); layout->setColumnStretch(0, 1); layout->setColumnStretch(1, 3); workspace->setLayout(layout); setCentralWidget(workspace); } void MainWindow::buildMenu(QMenuBar *mainMenu) { QMenu *fileMenu = new QMenu(tr("File")); QAction *newAct = new QAction(tr("&New"), this); QAction *openAct = new QAction(tr("&Open Database..."), this); QAction *saveAct = new QAction(tr("&Save"), this); QAction *svasAct = new QAction(tr("&Save As..."), this); QAction *exitAct = new QAction(tr("E&xit"), this); exitAct->setShortcut(tr("Ctrl+Q")); exitAct->setStatusTip(tr("Exit the application")); connect(exitAct, SIGNAL(triggered()), this, SLOT(close())); openAct->setShortcut(tr("Ctrl+O")); openAct->setStatusTip(tr("Open database")); connect(openAct, SIGNAL(triggered()), this, SLOT(open())); saveAct->setShortcut(tr("Ctrl+S")); saveAct->setStatusTip(tr("Save database")); connect(saveAct, SIGNAL(triggered()), this, SLOT(save())); newAct->setShortcut(tr("Ctrl+N")); newAct->setStatusTip(tr("Create new database")); connect(newAct, SIGNAL(triggered()), this, SLOT(createNew())); saveAct->setStatusTip(tr("Save database as...")); connect(svasAct, SIGNAL(triggered()), this, SLOT(saveAs())); fileMenu->addAction(newAct); fileMenu->addAction(openAct); fileMenu->addAction(saveAct); fileMenu->addAction(svasAct); fileMenu->addAction(exitAct); mainMenu->addMenu(fileMenu); setMenuBar(mainMenu); } // Constructor MainWindow::MainWindow() { QMenuBar *menu = new QMenuBar(); workspace = new QWidget(); workspace->setObjectName("window proper"); memset(NumObjects, 0, sizeof NumObjects); drawWindow(); buildMenu(menu); setWindowTitle(tr("Open BACnet Database Editor")); resize(800, 600); bModified = false; bDBLoaded = false; createNew(); } MainWindow::~MainWindow() { if(tempFilename != NULL) QFile::remove(tempFilename); }