summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Jones <admin@danieljon.es>2019-04-07 11:07:57 +0930
committerDaniel Jones <admin@danieljon.es>2019-04-07 11:07:57 +0930
commite38858efb7c8904352f9c4c1dea403b53a7a99f4 (patch)
tree5577b93bf7c530cf40a84036adba90ec2d1db9b7
downloadproductinventory-e38858efb7c8904352f9c4c1dea403b53a7a99f4.tar.gz
productinventory-e38858efb7c8904352f9c4c1dea403b53a7a99f4.zip
first code, basic program works
-rw-r--r--ProductInventory.pro42
-rw-r--r--database.cpp151
-rw-r--r--dbdesign/database.mwbbin0 -> 6988 bytes
-rw-r--r--generic.cpp29
-rw-r--r--main.cpp29
-rw-r--r--productinventory.cpp230
-rw-r--r--productinventory.h77
-rw-r--r--productinventory.ui433
8 files changed, 991 insertions, 0 deletions
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 <http://www.gnu.org/licenses/>.
+ */
+
+#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<QString> 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
--- /dev/null
+++ b/dbdesign/database.mwb
Binary files 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "productinventory.h"
+#include <QApplication>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#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<QTableWidget *>::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<QString> with values to add to the new row
+ */
+void
+ProductInventory::addItemToTable(QTableWidget *table, QList<QString> *values)
+{
+ QList<QString>::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<QTableWidget *>::iterator i;
+ for (i = tables.begin(); i != tables.end(); i++)
+ {
+ (*i)->setRowCount(0);
+ (*i)->hide();
+ delete (*i);
+ tables.erase(i);
+ }
+ QList<QLabel *>::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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PRODUCTINVENTORY_H
+#define PRODUCTINVENTORY_H
+
+#include <QMainWindow>
+#include <QStatusBar>
+#include <QSqlDatabase>
+#include <QSqlQuery>
+#include <QSqlError>
+#include <QMessageBox>
+#include <QTableWidgetItem>
+#include <QDebug>
+
+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<QString> *values); // add item to the specified table with the provided values
+ void clearTables(); // clear and delete every QTabeWidgetItem in each table
+ QList<QTableWidget *> 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<QLabel *> 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProductInventory</class>
+ <widget class="QMainWindow" name="ProductInventory">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>583</width>
+ <height>484</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>ProductInventory</string>
+ </property>
+ <widget class="QWidget" name="centralWidget">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTabWidget" name="mainTabs">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Ignored" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="currentIndex">
+ <number>1</number>
+ </property>
+ <widget class="QWidget" name="dbConTab">
+ <attribute name="title">
+ <string>Database</string>
+ </attribute>
+ <layout class="QFormLayout" name="formLayout_4">
+ <item row="0" column="0">
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="hostLabel">
+ <property name="text">
+ <string>Host</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLineEdit" name="HostInput">
+ <property name="text">
+ <string>localhost</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QSpinBox" name="portInput">
+ <property name="maximum">
+ <number>9999</number>
+ </property>
+ <property name="value">
+ <number>3306</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="portLabel">
+ <property name="text">
+ <string>Port</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0">
+ <layout class="QFormLayout" name="formLayout">
+ <item row="1" column="0">
+ <widget class="QLineEdit" name="usernameInput">
+ <property name="text">
+ <string>inventory</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="usernameLabel">
+ <property name="text">
+ <string>Username</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="passwordLabel">
+ <property name="text">
+ <string>Password</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="passwordInput">
+ <property name="font">
+ <font>
+ <strikeout>false</strikeout>
+ </font>
+ </property>
+ <property name="text">
+ <string>inventorypassword</string>
+ </property>
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QPushButton" name="connectButton">
+ <property name="text">
+ <string>Connect</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLineEdit" name="databaseInput">
+ <property name="text">
+ <string>ProductInventory</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="databaseLabel">
+ <property name="text">
+ <string>Database</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="filterTab">
+ <attribute name="title">
+ <string>Filter</string>
+ </attribute>
+ <layout class="QFormLayout" name="formLayout_6">
+ <item row="0" column="0">
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="1" column="0">
+ <widget class="QLabel" name="filterBrandsLabel">
+ <property name="text">
+ <string>Filter brands</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="IncludesTextBrandsLabel">
+ <property name="text">
+ <string>Includes text:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="includesTextBrandsInput">
+ <property name="minimumSize">
+ <size>
+ <width>115</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="1">
+ <layout class="QFormLayout" name="formLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="filterProductsLabel">
+ <property name="text">
+ <string>Filter products</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="filterCategoryLabel">
+ <property name="text">
+ <string>Category</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="filterCategoryComboBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>115</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="includesTextProductsLabel">
+ <property name="text">
+ <string>Includes text:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="includesTextProductsInput">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>115</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QCheckBox" name="mustHaveImagesCheckBox">
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string>Must have images</string>
+ </property>
+ <property name="tristate">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QCheckBox" name="mustNotHaveImagesCheckBox">
+ <property name="text">
+ <string>Must not have images</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <widget class="QPushButton" name="pushButton">
+ <property name="text">
+ <string>Filter</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <layout class="QFormLayout" name="formLayout_5">
+ <item row="0" column="0">
+ <widget class="QLabel" name="statsLabel">
+ <property name="text">
+ <string>Stats:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="statsHereLabel">
+ <property name="text">
+ <string>STATS_PLACEHOLDER</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QScrollArea" name="scrollArea">
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>563</width>
+ <height>165</height>
+ </rect>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QTableWidget" name="tableWidget">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Sunken</enum>
+ </property>
+ <property name="verticalScrollBarPolicy">
+ <enum>Qt::ScrollBarAsNeeded</enum>
+ </property>
+ <property name="sizeAdjustPolicy">
+ <enum>QAbstractScrollArea::AdjustToContentsOnFirstShow</enum>
+ </property>
+ <property name="autoScroll">
+ <bool>true</bool>
+ </property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>false</bool>
+ </property>
+ <property name="verticalScrollMode">
+ <enum>QAbstractItemView::ScrollPerItem</enum>
+ </property>
+ <property name="showGrid">
+ <bool>true</bool>
+ </property>
+ <property name="sortingEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <attribute name="horizontalHeaderCascadingSectionResizes">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="horizontalHeaderStretchLastSection">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="verticalHeaderStretchLastSection">
+ <bool>false</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>Brand</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Colour</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Comment</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menuBar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>583</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menuFile">
+ <property name="title">
+ <string>File</string>
+ </property>
+ <addaction name="actionExit"/>
+ </widget>
+ <addaction name="menuFile"/>
+ </widget>
+ <widget class="QStatusBar" name="statusBar"/>
+ <action name="actionExit">
+ <property name="text">
+ <string>Exit</string>
+ </property>
+ </action>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <tabstops>
+ <tabstop>HostInput</tabstop>
+ <tabstop>portInput</tabstop>
+ <tabstop>usernameInput</tabstop>
+ <tabstop>passwordInput</tabstop>
+ <tabstop>databaseInput</tabstop>
+ <tabstop>connectButton</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>actionExit</sender>
+ <signal>triggered()</signal>
+ <receiver>ProductInventory</receiver>
+ <slot>close()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>261</x>
+ <y>250</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>