From e38858efb7c8904352f9c4c1dea403b53a7a99f4 Mon Sep 17 00:00:00 2001 From: Daniel Jones Date: Sun, 7 Apr 2019 11:07:57 +0930 Subject: first code, basic program works --- ProductInventory.pro | 42 +++++ database.cpp | 151 ++++++++++++++++++ dbdesign/database.mwb | Bin 0 -> 6988 bytes generic.cpp | 29 ++++ main.cpp | 29 ++++ productinventory.cpp | 230 +++++++++++++++++++++++++++ productinventory.h | 77 +++++++++ productinventory.ui | 433 ++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 991 insertions(+) create mode 100644 ProductInventory.pro create mode 100644 database.cpp create mode 100644 dbdesign/database.mwb create mode 100644 generic.cpp create mode 100644 main.cpp create mode 100644 productinventory.cpp create mode 100644 productinventory.h create mode 100644 productinventory.ui diff --git a/ProductInventory.pro b/ProductInventory.pro new file mode 100644 index 0000000..4f61339 --- /dev/null +++ b/ProductInventory.pro @@ -0,0 +1,42 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2019-04-04T11:25:52 +# +#------------------------------------------------- + +QT += core gui sql + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = ProductInventory +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + productinventory.cpp \ + database.cpp \ + generic.cpp + +HEADERS += \ + productinventory.h + +FORMS += \ + productinventory.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/database.cpp b/database.cpp new file mode 100644 index 0000000..c079238 --- /dev/null +++ b/database.cpp @@ -0,0 +1,151 @@ +/* + * database.cpp is a part of ProductInventory + * An inventory system designed for makeup and related things + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "productinventory.h" +#include "ui_productinventory.h" + + +/*! + * connect to database + * \return connect success or fail + */ +bool +ProductInventory::dbConnect() +{ + db.setHostName(ui->HostInput->text()); + db.setPort(ui->portInput->value()); + db.setDatabaseName(ui->databaseInput->text()); + db.setUserName(ui->usernameInput->text()); + db.setPassword(ui->passwordInput->text()); + bool status = db.open(); + if (status) + { + isConnected = true; + conStatus = "Connected"; + conColor = "darkgreen"; + statusMessage("", 0); + ui->connectButton->setText("Disconnect"); + return true; + } + qDebug() << "sql connection failed:" << db.lastError().text(); + return false; +} + +/*! + * disconnect from database + * \return disconnect success or fail + */ +bool +ProductInventory::dbDisconnect() +{ + db.close(); + isConnected = false; + conStatus = "Disconnected"; + conColor = "red"; + statusMessage("", 0); + ui->connectButton->setText("Connect"); + return true; +} + +bool +ProductInventory::getConnectionStatus() +{ + return isConnected; +} + +/*! + * runs a generic query on the database and returns a pointer to a new + * QSqlQuery which must be deleted + * \param query the query to run + * \return + */ +QSqlQuery * +ProductInventory::genericQuery(QString query) +{ + QSqlQuery *q = new QSqlQuery; + if (!q->exec(query)) + { + qDebug() << "query execute failed:" << q->lastError().text(); + genericMessageBox(q->lastError().text(), "query error"); + delete q; + return nullptr; + } + return q; + +} + +/*! + * populates the user interface elements with data from the database + */ +void +ProductInventory::populateInterface() +{ + ui->filterCategoryComboBox->clear(); + QSqlQuery *query = genericQuery("SELECT * FROM category;"); + if (query == nullptr) + { + qDebug() << "failed to populate interface"; + } + else + { + while (query->next()) + { + QString name = query->value(2).toString(); + ui->filterCategoryComboBox->addItem(name); + } + delete query; + } + + //query = genericQuery("SELECT brand, color, comment FROM product"); + query = genericQuery("SELECT categoryid, name FROM category"); + if (query == nullptr) + { + qDebug() << "failed to populate interface"; + } + else + { + while (query->next()) + { + int t = createTable(query->value(1).toString()); + if (t == -1) + { + qDebug() << "failed to populate interface"; + delete query; + return; + + } + QSqlQuery *inner = genericQuery("SELECT brand, color, comment FROM product WHERE categoryid="+query->value(0).toString()); + if (inner == nullptr) + { + qDebug() << "failed to populate interface"; + delete query; + return; + } + while (inner->next()) + { + QList item; + item.append(inner->value(0).toString()); + item.append(inner->value(1).toString()); + item.append(inner->value(2).toString()); + addItemToTable(tables.at(t), &item); + } + delete inner; + } + delete query; + } +} diff --git a/dbdesign/database.mwb b/dbdesign/database.mwb new file mode 100644 index 0000000..947cc04 Binary files /dev/null and b/dbdesign/database.mwb differ diff --git a/generic.cpp b/generic.cpp new file mode 100644 index 0000000..dcd08cb --- /dev/null +++ b/generic.cpp @@ -0,0 +1,29 @@ +/* + * generic.cpp is a part of ProductInventory + * An inventory system designed for makeup and related things + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "productinventory.h" +#include "ui_productinventory.h" + +void +ProductInventory::genericMessageBox(QString msg, QString title) +{ + QMessageBox box; + box.setText(msg); + box.setWindowTitle(title); + box.exec(); +} diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..6bc4d3d --- /dev/null +++ b/main.cpp @@ -0,0 +1,29 @@ +/* + * main.cpp is a part of ProductInventory + * An inventory system designed for makeup and related things + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "productinventory.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + ProductInventory w; + w.show(); + + return a.exec(); +} diff --git a/productinventory.cpp b/productinventory.cpp new file mode 100644 index 0000000..6b26aa0 --- /dev/null +++ b/productinventory.cpp @@ -0,0 +1,230 @@ +/* + * productinventory.cpp is a part of ProductInventory + * An inventory system designed for makeup and related things + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "productinventory.h" +#include "ui_productinventory.h" + +/*! + * constructor + * \param parent parent + */ +ProductInventory::ProductInventory(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::ProductInventory) +{ + ui->setupUi(this); + /* database and statusbar init */ + db = QSqlDatabase::addDatabase("QMYSQL"); + conStatus = "Disconnected"; + conColor = "red"; + isConnected = false; + statusMessage(conStatus, conColor, 0); + + /* make column headers resize to fit display */ + ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + + /* signal/slot connections */ + connect(ui->statusBar, SIGNAL(messageChanged(const QString)), this, SLOT(statusChanged(QString))); + + ui->tableWidget->hide(); + headerLabels.append(QString("Brand")); + headerLabels.append(QString("Color")); + headerLabels.append(QString("Comment")); +} + +/*! + * destructor + */ +ProductInventory::~ProductInventory() +{ + clearTables(); + delete ui; +} + +/*! + * write a message to the statusbar + * \param msg message to display + * \param color text color + * \param ms milliseconds to show message (0 = forever until overwritten) + */ +void +ProductInventory::statusMessage(QString msg, QString color, int ms) +{ + ui->statusBar->setStyleSheet("color: " + color); + ui->statusBar->showMessage(msg, ms); +} + +/*! + * overload for writing a message to the status bar without a color (defaults to black) + * \param msg message to display + * \param ms milliseconds to show message (0 = forever until overwritten) + */ +void +ProductInventory::statusMessage(QString msg, int ms) +{ + statusMessage(msg, "black", ms); +} + +/*! + * slot to receive signal when statusbar message changes + * \param msg new message + */ +void +ProductInventory::statusChanged(QString msg) +{ + /* + * if we have an empty message, display the connection status + * indefinitely (empty message received when it is cleared) + * BUG: called on hover in file menu + */ + if (msg == "") + statusMessage(conStatus, conColor, 0); +} + +/*! + * slot to receive signal when the connect button is clicked + */ +void +ProductInventory::on_connectButton_clicked() +{ + /* + * we use the one button for both connect and disconnect, + * so we need to keep track of our status in isConnected + * change the button appropriately + */ + if (getConnectionStatus()) + { + // TODO log + if (dbDisconnect()) + { + qDebug() << "Disconnected from database"; + } + } + else + { + db.setHostName(ui->HostInput->text()); + db.setPort((ui->portInput->value())); + db.setUserName(ui->usernameInput->text()); + db.setPassword(ui->passwordInput->text()); + if (dbConnect()) + { + // TODO log + qDebug() << "Connected to database"; + clearTables(); + populateInterface(); + } + } +} + +/*! + * called when window is resized + * \param event + */ +void +ProductInventory::resizeEvent(QResizeEvent* event) +{ + QMainWindow::resizeEvent(event); + ui->tableWidget->resizeRowsToContents(); // not needed? + QList::iterator i; + for (i = tables.begin(); i != tables.end(); i++) + { + (*i)->resizeRowsToContents(); + } +} + +void ProductInventory::on_mustHaveImagesCheckBox_clicked() +{ + ui->mustNotHaveImagesCheckBox->setChecked(false); +} + +void ProductInventory::on_mustNotHaveImagesCheckBox_clicked() +{ + ui->mustHaveImagesCheckBox->setChecked(false); +} + +/*! + * add a single item (row) to the table + * \param table the table object to add the item to + * \param values QList with values to add to the new row + */ +void +ProductInventory::addItemToTable(QTableWidget *table, QList *values) +{ + QList::iterator i; + int col = 0; + int row = ui->tableWidget->rowCount(); + table->insertRow(row); + for (i = values->begin(); i != values->end(); i++) + { + QTableWidgetItem *test1 = new QTableWidgetItem(*i); + table->setItem(row, col, test1); + col++; + } +} + +/*! + * clear the default table and all other added tables + * by iterating through the tables list + */ +void +ProductInventory::clearTables() +{ + qDebug() << "clearing table and deleting items"; + ui->tableWidget->setRowCount(0); // automagically deletes items + QList::iterator i; + for (i = tables.begin(); i != tables.end(); i++) + { + (*i)->setRowCount(0); + (*i)->hide(); + delete (*i); + tables.erase(i); + } + QList::iterator l; + for (l = labels.begin(); l != labels.end(); l++) + { + (*l)->hide(); + labels.erase(l); + } +} + +/*! + * create a QTableWidget, set some properties, append to tables list + * \return index into tables or -1 on error + */ +int +ProductInventory::createTable(QString category) +{ + QTableWidget *table = new QTableWidget; + if (table == nullptr) + return -1; + table->setMinimumHeight(100); + table->setColumnCount(3); + table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + table->setHorizontalHeaderLabels(headerLabels); + table->verticalHeader()->hide(); + QLabel *label = new QLabel(category); + if (label == nullptr) + return -1; + labels.append(label); + QFont f( "Arial", 10, QFont::Bold); + label->setFont(f); + ui->scrollArea->widget()->layout()->addWidget(label); + ui->scrollArea->widget()->layout()->addWidget(table); + tables.append(table); + return tables.size()-1; +} diff --git a/productinventory.h b/productinventory.h new file mode 100644 index 0000000..34df6c4 --- /dev/null +++ b/productinventory.h @@ -0,0 +1,77 @@ +/* + * productinventory.h a part of ProductInventory + * An inventory system designed for makeup and related things + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef PRODUCTINVENTORY_H +#define PRODUCTINVENTORY_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Ui { +class ProductInventory; +} + +class ProductInventory : public QMainWindow +{ + Q_OBJECT + +public: + explicit ProductInventory(QWidget *parent = nullptr); + ~ProductInventory(); + bool getConnectionStatus(); // get database connection status + + void statusMessage(QString msg, int ms); // overload, show message in status bar for ms milliseconds + void statusMessage(QString msg, QString color, int ms); // show message in status bar for ms milliseconds + void genericMessageBox(QString msg, QString title); // display a generic message box + QSqlQuery *genericQuery(QString query); // run generic query and return a pointer to the new object + +private slots: + void statusChanged(QString msg); // called when the status bar value is changed + void on_connectButton_clicked(); // called when the connect button is pressed + + void on_mustHaveImagesCheckBox_clicked(); // called when must have images filter selected + void on_mustNotHaveImagesCheckBox_clicked(); // called when must not have images filter selected + +private: + Ui::ProductInventory *ui; + QString conStatus; // connection status text + QString conColor; // color of current connection status + bool isConnected; // store our conection status + + bool dbConnect(); // connect to database + bool dbDisconnect(); // disconnect from database + QSqlDatabase db; // database object + void resizeEvent(QResizeEvent *event); // called when the window is resized + void populateInterface(); // called when we want to populate interface elements + void addItemToTable(QTableWidget *table, + QList *values); // add item to the specified table with the provided values + void clearTables(); // clear and delete every QTabeWidgetItem in each table + QList tables; // store our tables + int createTable(QString category); // create a table and add it to our tables list with a header, returns index in list or -1 + QStringList headerLabels; // labels used for table headers + QList labels; // labels used for table names + +}; + +#endif // PRODUCTINVENTORY_H diff --git a/productinventory.ui b/productinventory.ui new file mode 100644 index 0000000..2837b39 --- /dev/null +++ b/productinventory.ui @@ -0,0 +1,433 @@ + + + ProductInventory + + + + 0 + 0 + 583 + 484 + + + + ProductInventory + + + + + + + + 0 + 0 + + + + 1 + + + + Database + + + + + + + + Host + + + + + + + localhost + + + + + + + 9999 + + + 3306 + + + + + + + Port + + + + + + + + + + + inventory + + + + + + + Username + + + + + + + Password + + + + + + + + false + + + + inventorypassword + + + QLineEdit::Password + + + + + + + Connect + + + + + + + ProductInventory + + + + + + + Database + + + + + + + + + + Filter + + + + + + + + Filter brands + + + + + + + Includes text: + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 115 + 0 + + + + + + + + + + + + Filter products + + + + + + + Category + + + + + + + + 0 + 0 + + + + + 115 + 0 + + + + + + + + Includes text: + + + + + + + + 0 + 0 + + + + + 115 + 0 + + + + + + + + Qt::LeftToRight + + + Must have images + + + false + + + + + + + Must not have images + + + + + + + + + Filter + + + + + + + + + Stats: + + + + + + + STATS_PLACEHOLDER + + + + + + + + + + + + + true + + + + + 0 + 0 + 563 + 165 + + + + + + + + 0 + 0 + + + + + 0 + 100 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustToContentsOnFirstShow + + + true + + + QAbstractItemView::NoEditTriggers + + + false + + + QAbstractItemView::ScrollPerItem + + + true + + + false + + + true + + + true + + + true + + + false + + + false + + + + Brand + + + + + Colour + + + + + Comment + + + + + + + + + + + + + + 0 + 0 + 583 + 20 + + + + + File + + + + + + + + + Exit + + + + + + HostInput + portInput + usernameInput + passwordInput + databaseInput + connectButton + + + + + actionExit + triggered() + ProductInventory + close() + + + -1 + -1 + + + 261 + 250 + + + + + -- cgit v1.2.3