C++ Hashtable issues within a nested switch case - hashtable

So i am having an issue with a hashtable functions. In the main function the hashtables functions(removeitem, insertItem, and printTable) work with no issue but when i attempt to call them within another function AdminMenu they do not seem to work. For example when I run the program i can get the AdminMenu with no issues but once in the Admin menu a selection of an option produces the cout statement but does not complete the function. For example when you select 3 to print table nothing is output but the number 3. This function works when the function is called at the start of main but calling it inside the nested switch case adn it does not preform the function of printTable just outputs the selection 3.
#include<list>
#include<limits>
#include<string>
using namespace std;
// GLOBAL VARIABLES
bool empMatch= false; //set to false
bool keyExists = false;//set to false
//HASH TABLE CLASS STRUCT
class HashTable{
private:
static const int hashGroups = 10; //total size of 10 can be increased for larger groups
list<pair<int, string>> table[hashGroups];
public:
bool isEmpty();
int hashFunction(int key);
void insertItem(int key, string value);
void removeItem(int key);
bool searchTable(int key,string value);
void printTable();
};
//HASH FUNCTION TO CHECK IF TABLE EMPTY
bool HashTable::isEmpty()
{
int sum{};
for(int i{}; i< hashGroups; i++){
sum += table[i].size();
}
if(!sum){
return true;
}
return false;
}
//HASH FUNCTION
int HashTable::hashFunction(int key){
return key % hashGroups;
}
//HASH FUNCTION FOR INSERT VALUE
void HashTable::insertItem(int key, string value){
int hashValue = hashFunction(key);
auto& cell = table[hashValue];
auto tItr = begin(cell);
for(; tItr != end(cell); tItr++){
if(tItr->first==key){
keyExists = true; //if key exists replace value
tItr->second = value; //becomes value of input
cout<<"Warning key exists. value replaced\n";
break;
}
}
if (!keyExists){// If key does not exist then put back key and value
cell.emplace_back(key,value);
}
return ;
}
//HASH FUNCTION REMOVE
void HashTable::removeItem(int key){
int hashValue = hashFunction(key);
auto& cell = table[hashValue];
auto tItr = begin(cell);
for(; tItr != end(cell); tItr++){
if(tItr->first==key){
keyExists = true;
tItr = cell.erase(tItr);
cout<<"item removed\n";
break;
}
}
if(!keyExists){
cout<<"warning key not found";
}
return;
}
//HASH SEARCH TABLE FUNCTION FOR USER INPUT KEY AND USER INPUT VALUE
bool HashTable::searchTable(int key, string value){
int hashValue = hashFunction(key); //hash function to key input
auto& cell = table[hashValue];
auto tItr = begin(cell); //iterator
for(; tItr != end(cell); tItr++){
if(tItr->first==key){
keyExists = true;
if(keyExists){
if(tItr->second==value){//tests value of input is matching
empMatch=true;
}
else{
cout<<"access denied\n";
empMatch=false;
}
}
if(!keyExists){
cout<<"warning key not found\n";
empMatch= false;
}
}
}
return empMatch;
}
//HASH PRINT TABLE FUNCTION
void HashTable::printTable(){
for (int i{}; i< hashGroups ; i++){
if (table[i].size() == 0) continue;
auto tItr = table[i].begin();
for(;tItr !=table[i].end(); tItr++){
cout<<"info key : "<< tItr->first<<" value "<< tItr->second<<endl;
}
}
return;
}
//ADMIN MENU AND FUNCTIONS
void AdminMenu(){
int adminChoice=0;
int adminKey =0;
string adminValue;
HashTable HT;
cout<<"Please select from the following menu:\n";
cout<<"Option 1 insert user\n";
cout<<"Option 2 remove user\n";
cout<<"Option 3 Print user list\n";
cout<<"OPtion 4 Exit\n";
cin>>adminChoice;
switch(adminChoice){
case 1:
cout<<"Please enter employee id (whole number integer) to insert\n";
cin>>adminKey;
cout<<"Please enter password for employee id\n";
cin>>adminValue;
HT.insertItem(adminKey,adminValue);// DOESNT SEEM TO WORK
cout<<"insertion complete\n";
AdminMenu();
case 2:
cout<<"Please enter employee id (whole number integer) to remove\n";
cin>>adminKey;
HT.removeItem(adminKey); //DOESNT' SEEM TO WORK
cout<<"removal complete\n";
AdminMenu();
case 3:
HT.printTable(); //DOESN'T SEEM TO WORK.
AdminMenu();
case 4:
exit(0);
break;
}
}
//TODO implement a function that checks password against database or hashmap
void DisplayInfo(){
string clients[2][5] = {{"Bob Jones","Sarah Davis","Amy Friendly","Johnny Smith","Carol Spears"},{"2","2","1","1","2"}};
cout << "You chose 1\n" << "Client's Name Service Selected (1 = Brokerage, 2 = Retirement)\n";
for(int i=0;i<5;i++) {
cout << clients[0][i] << " selected option " << clients[1][i] << endl;
}
}
void changeCustomerChoice(){
string clients[2][5] = {{"Bob Jones","Sarah Davis","Amy Friendly","Johnny Smith","Carol Spears"},{"","2","1","1","2"}};
int temp= 0; //intialized at 0
cout << "You chose 2\n";
cout << "Enter the number of client you wish to change : \n";
cin >> temp; //this will check the type of input by the user.
while(1){ //this is an infinite check for the cin
if (cin.fail()){//this returns true when input failure occurs
cin.clear();// this clears the error state of the buffer
cin.ignore(numeric_limits<streamsize>::max(),'\n');//ignores the first instance of error
cout<<"You have entered the wrong input";
break;
}
if(temp>5||temp<1){
cin.clear();
cout<<"Selection out of range";
break;
}
if(!cin.fail()){// allow selection of services if input is correct
cout << "Please enter the client's new service choice (1 = Brokerage, 2 = Retirement)\n";
cin >> clients[1][temp-1]; //input needs to be adjusted to limit only 1 or 2 for change to new service
cout << "Changed option to : "<<clients[1][temp-1];
break;
}
}
}
int main()
{
HashTable HT;
int empNum= 0;
string empPass;
int userChoice;
int adminPass;
//insert values to i dont have a empty table
HT.insertItem(905,"Jim");
HT.insertItem(9415,"bob");
HT.insertItem(5105,"sany");
HT.insertItem(685,"Jasdfm");
HT.insertItem(9565,"amrk");
HT.insertItem(905,"trick");
HT.printTable();
cout<<"please enter employee number\n";
cout<<"please enter employee password\n";
cin>>empNum;
cin>>empPass;
HT.searchTable(empNum,empPass);
if(empMatch){
cout<<"access granted";
cout<<"What would you like to do?\n";
cout<<"DISPLAY the client list (enter1)\n";
cout<<"CHANGE a clients choice (enter2)\n";
cout<<"Admin functions (enter3)\n";
cout<<"Exit the program(enter4)\n";
cin>> userChoice;
switch(userChoice){
case 1:
DisplayInfo();
main();
break;
case 2:
changeCustomerChoice();
main();
break;
case 3:
cout<<"Please enter admin password\n";
cin>> adminPass;
if(adminPass == 5691){
AdminMenu();
break;
}
else{
break;
}
case 4:
exit(0); //exit program
default: //secures input from usering being malicious in nature
cout << "Invalid Selection" << endl;
cin.clear(); //clears the error state of the buffer
main(); // got back to main function
}
}
if(!empMatch){
cout<<"The creditionals you have entered do not match\n";
exit(0);
}
return 0;
`

Related

How to create a QVariant-based generic model?

Quite often I find myself in need of some custom scheme model, mandating the implementation of more and more models, made even more tedious by the inability of QObject derived classes to be templates.
Qt has the QStandardItemModel but that seems a bit verbose and inconvenient to use, especially from the qml side, and total overkill for a basic list model.
There is also the basic qml ListModel, but that is limited and not elegant to use on the C++ side, and I do suspect a tad more bloated than it needs to be.
Qt has QVariant, which is what its model/view architecture uses internally, so it is surprising that the framework doesn't provide something as simple as:
// qml code
VarMod {
roles: ["name", "age", "weight"]
Component.onCompleted: {
insert(["Jack", 34, 88.5], -1) // qml doesn't support
insert(["Mary", 26, 55.3], -1) // default arg values
}
}
// cpp code
VarMod vm { "name", "age", "weight" }; // member declaration
vm.insert({ "Jack", 34, 88.5 });
vm.insert({ "Mary", 26, 55.3 });
And here it is.
Note that you do have to be responsible with the parameters, as there is no type safety, in fact it has implicit analog to ListModel's dynamicRoles - that is, it will accept and work with any QVariant compatible value on every role slot.
As for memory efficiency, consider that QVariant has 8 bytes for data, plus 4 bytes for type id, plus another 4 bytes of padding, for a total of 16 bytes. That is not insignificant if you are using it for small data types, like say bool, so in case you have a data scheme that has a lot of small (1 - 4 bytes) fields and a scores of items, implementing a full model will still be the better option. It is still a lot better than the generic object model I am using, which has to carry the bloat of QObject, and even more significant in the case of qml objects.
Additionally, QVariant being 16 bytes, I opted to not use the convenience of QVariantList for data storage, which has an underlying QList, making the situation worse than it needs to be. Although that is fixed in Qt 6, which gets rid of QList as it is, and replaces it with an alias of QVector. Still, std::vector helps to avoid that in any case, plus it might actually be a tad faster, since it doesn't have to deal with COW and atomic ref counters. There are several auxiliary methods to help with pre-allocation and release of memory as well.
The model has a safeguard against the change the roles for obvious reasons, the latter is primarily intended to be initialized just once, but there is reset() that is intended to be used in a more dynamic qml context, making it possible to redefine the model schema on the fly and provide a compatible delegate. For the sake of certainty, the roles can only be redefined after the model has been explicitly reset.
There is a minute difference in inserting, on the c++ side, the parameter pack is passed wrapped in {}, in qml it is wrapped in [], both leveraging implicit conversion in the context specific way. Also, note that qml currently doesn't support omitting parameters with default values provided on the c++ side, so for appending you do have to provide an invalid index. Naturally, it would be trivial to add convenience methods for appending and prepending if needed.
In addition to the syntax example of the question, it is also possible to add multiple items at once, from "declarative-y" qml structure such as:
let v = [["Jack", 34, 88.5],
["Mary", 26, 55.3],
["Sue", 22, 69.6]]
vm.insertList(v, -1)
Finally, type safety is possible to implement if the scenario really calls for it, then each role can be specified with the expected type to go with it, such as:
VarMod vm {{"name", QMetaType::QString},
{"age", QMetaType::Int},
{"weight", QMetaType::QReal}};
and then iterating and making the necessary checks to ensure type safety when inserting.
Update: I also added serialization, and save/load from disk features, note that this will serialize the data together with the mode schema.
class VarMod : public QAbstractListModel {
Q_OBJECT
Q_PROPERTY(QVariantList roles READ roles WRITE setRoles NOTIFY rolesChanged)
QVariantList vroles;
QVariantList roles() const { return vroles; }
QHash<int, QByteArray> _roles;
std::vector<std::vector<QVariant>> _data;
inline bool checkArgs(int rc) const {
if (rc == _roles.size()) return true;
qWarning() << "arg size mismatch, got / expected" << rc << _roles.size();
return false;
}
inline bool inBounds(int i, bool ok = false) const {
if (i > -1 && i < (int)_data.size()) return true;
if (!ok) qWarning() << "out of bounds" << i; // do not warn if intentionally appending
return false;
}
inline bool validRole(int r) const { return (r > -1 && r < _roles.size()); }
protected:
QHash<int, QByteArray> roleNames() const override { return _roles; }
int rowCount(const QModelIndex &) const override { return _data.size(); }
QVariant data(const QModelIndex &index, int r) const override {
r = r - Qt::UserRole - 1;
if (inBounds(index.row()) && validRole(r)) return _data[index.row()][r];
return QVariant();
}
public:
VarMod() {} // for qml
VarMod(std::initializer_list<QByteArray> r) {
int rc = Qt::UserRole + 1;
for (const auto & ri : r) {
_roles.insert(rc++, ri);
vroles << QString::fromLatin1(ri);
}
rolesChanged();
}
inline void insert(std::initializer_list<QVariant> s, int i = -1) {
if (!checkArgs(s.size())) return;
insert(QVariantList(s), i);
}
inline bool setItem(int i, std::initializer_list<QVariant> s) {
if (checkArgs(s.size())) return setItem(i, QVariantList(s));
return false;
}
void setRoles(QVariantList r) {
if (_roles.empty()) {
int rc = Qt::UserRole + 1;
for (const auto & vi : r) _roles.insert(rc++, vi.toByteArray());
vroles = r;
rolesChanged();
} else qWarning() << "roles are already initialized";
}
void read(QDataStream & d) {
reset();
QVariantList vr;
d >> vr;
quint32 s;
d >> s;
_data.resize(s);
for (uint i = 0; i < s; ++i) {
_data[i].reserve(vr.size());
for (int c = 0; c < vr.size(); ++c) {
QVariant var;
d >> var;
_data[i].push_back(std::move(var));
}
}
setRoles(vr);
beginResetModel();
endResetModel();
}
void write(QDataStream & d) const {
d << vroles;
d << (quint32)_data.size();
for (const auto & v : _data) {
for (const auto & i : v) d << i;
}
}
public slots:
void insert(QVariantList s, int i) {
if (!inBounds(i, true)) i = _data.size();
if (!checkArgs(s.size())) return;
beginInsertRows(QModelIndex(), i, i);
_data.insert(_data.begin() + i, { s.cbegin(), s.cend() });
endInsertRows();
}
void insertList(QVariantList s, int i) {
if (!inBounds(i, true)) i = _data.size();
int added = 0;
for (const auto & il : s) {
QVariantList ll = il.value<QVariantList>();
if (checkArgs(ll.size())) {
_data.insert(_data.begin() + i + added++, { ll.cbegin(), ll.cend() });
}
}
if (added) {
beginInsertRows(QModelIndex(), i, i + added - 1);
endInsertRows();
}
}
bool setData(int i, int r, QVariant d) {
if (!inBounds(i) || !validRole(r)) return false;
_data[i][r] = d;
dataChanged(index(i), index(i));
return true;
}
bool setDataStr(int i, QString rs, QVariant d) { // a tad slower
int r = _roles.key(rs.toLatin1()); // role is resolved in linear time
if (r) return setData(i, r - Qt::UserRole - 1, d);
qWarning() << "invalid role" << rs;
return false;
}
bool setItem(int i, QVariantList d) {
if (!inBounds(i) || !checkArgs(d.size())) return false;
_data[i] = { d.cbegin(), d.cend() };
dataChanged(index(i), index(i));
return true;
}
QVariantList item(int i) const {
if (!inBounds(i)) return QVariantList();
const auto & v = _data[i];
return { v.begin(), v.end() };
}
QVariant getData(int i, int r) const {
if (inBounds(i) && validRole(r)) return _data[i][r];
return QVariant();
}
QVariant getDataStr(int i, QString rs) const {
int r = _roles.key(rs.toLatin1()); // role is resolved in linear time
if (r) return getData(i, r);
qWarning() << "invalid role" << rs;
return QVariant();
}
QVariantList take(int i) {
QVariantList res = item(i);
if (res.size()) remove(i);
return res;
}
bool swap(int i1, int i2) {
if (!inBounds(i1) || !inBounds(i2)) return false;
std::iter_swap(_data.begin() + i1, _data.begin() + i2);
dataChanged(index(i1), index(i1));
dataChanged(index(i2), index(i2));
return true;
}
bool remove(int i) {
if (!inBounds(i)) return false;
beginRemoveRows(QModelIndex(), i, i);
_data.erase(_data.begin() + i);
endRemoveRows();
return true;
}
void clear() {
beginResetModel();
_data.clear();
_data.shrink_to_fit();
endResetModel();
}
void reset() {
clear();
_roles.clear();
vroles.clear();
rolesChanged();
}
void reserve(int c) { _data.reserve(c); }
int size() const { return _data.size(); }
int capacity() const { return _data.capacity(); }
void squeeze() { _data.shrink_to_fit(); }
bool fromFile(QString path) {
QFile f(path);
if (!f.open(QIODevice::ReadOnly)) return false;
QDataStream d(&f);
read(d); // assumes correct data
return true;
}
bool toFile(QString path) const {
QFile f(path);
if (!f.open(QIODevice::WriteOnly)) return false;
QDataStream d(&f);
write(d);
return true;
}
signals:
void rolesChanged();
};
I also created this sorting/filtering view to supplement the model:
class View : public QSortFilterProxyModel {
Q_OBJECT
Q_PROPERTY(QJSValue filter READ filter WRITE set_filter NOTIFY filterChanged)
Q_PROPERTY(bool reverse READ reverse WRITE setReverse NOTIFY reverseChanged)
bool reverse() const { return _reverse; }
void setReverse(bool v) {
if (v == _reverse) return;
_reverse = v;
reverseChanged();
sort(0, (Qt::SortOrder)_reverse);
}
bool _reverse = false;
mutable QJSValue m_filter;
QJSValue & filter() const { return m_filter; }
void set_filter(QJSValue & f) {
if (!m_filter.equals(f))
m_filter = f;
filterChanged();
invalidateFilter();
}
}
public:
View(QObject *parent = 0) : QSortFilterProxyModel(parent) { sort(0, (Qt::SortOrder)_reverse); }
signals:
void filterChanged();
void reverseChanged();
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &) const override {
if (!m_filter.isCallable()) return true;
VarMod * vm = qobject_cast<VarMod *>(sourceModel());
if (!vm) {
qWarning() << "model is not varmod";
return true;
}
return m_filter.call({_engine->toScriptValue(vm->item(sourceRow))}).toBool();
}
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override {
VarMod * vm = qobject_cast<VarMod *>(sourceModel());
if (!vm) {
qWarning() << "model is not varmod";
return false;
}
return vm->getData(left.row(), sortRole()) < vm->getData(right.row(), sortRole());
}
};
For sorting, you just have to specify the sorting role, note that it is the index of the "column" rather than the int value from the roles hash. For filtering it works via a qml functor that receives the model item as a JS array, and expects to return a bool, a c++ functor can be easily added via std::function if needed. Also note that it needs a pointer to the actual qml engine.
View {
id: vv
sourceModel: vm
sortRole: sr.value
reverse: rev.checked
filter: { sa.value; o => o[1] < sa.value } // "capturing" sa.value to react to value changes
}

CS50 Pset 5 Hashtable issue

After creating a hash table and assigning each letter to a value for the table, i am noticing the first word output by the table for the beginning of every linked list is the same word. Somehow it seems I am transferring the entire dictionary to each array in the table even though I have attempted to separate them. Any assistance would be awesome! Thanks in advance
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char *word;
struct node *next;
}
node;
// Number of buckets in hash table
const unsigned int N = 25;
// Hash table
node *table[N];
char lowerword[LENGTH+1];
// Returns true if word is in dictionary else false
bool check(const char *word)
{
int bucketfind = 0;
int x = 0;
for (int b = word[x]; b != '\0';b = word[x], x++)
{
int lowertemp = tolower(word[x]);
if (x == 0)
{
bucketfind = lowertemp - 97;
}
char lowerfinal = lowertemp;
lowerword[x] = lowerfinal;
//printf("%c", lowerword[x]);
}
int wordlen = x + 1;
int pr = 0;
while (table[bucketfind] -> next != NULL)
{
int dwlen = strlen(table[bucketfind]-> word);
pr++;
//printf("%i, %i, %s, %i\n", pr, dwlen, table[bucketfind] -> word, bucketfind);
}
//TODO
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
int asciifirst = word[0];
int lowerfirst = tolower(asciifirst);
int bucketnum = lowerfirst - 97;
return bucketnum;
}
// Loads dictionary into memory, returning true if successful else false
int dictwords = 0;
//char *cword = (char*)malloc(sizeof(char)*46);
bool load(const char *dictionary)
{
char *cword = malloc(sizeof(char)*46);
FILE *dict = fopen(dictionary, "r");
if (dictionary == NULL)
{
return false;
}
int x = 0;
while ((fscanf(dict, "%s", cword) != EOF))
{
node *nword = malloc(sizeof(node));
nword -> word = cword;
nword -> next = NULL;
int bucket = hash(cword);
//printf("%i\n", bucket);
if (table[bucket] != NULL)
{
nword -> next = table[bucket];
table[bucket] = nword;
}
else
{
table[bucket]= nword;
}
dictwords++;
}
fclose(dict);
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
return dictwords;
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
// TODO
return false;
}
It's not just the first word; every word in the linked list is the same word (the last one read). cword gets 46 bytes of memory at a specific address here char *cword = malloc(sizeof(char)*46);. Every word from dictionary is read into that same address.

QNetworkAccessManager not emitting finished signal with this code

so i have been browsing the previous questions before about this issue, but i could not find a solution for my code.
cpp file of dialog
------------------------------------------------
#include "everesult.h"
#include "ui_everesult.h"
everesult::everesult(QWidget *parent) :
QDialog(parent),
ui1(new Ui::everesult)
{
ui1->setupUi(this);
}
everesult::~everesult()
{
delete ui1;
}
void everesult::setmodel(QStandardItemModel *model)
{
ui1->listView->setModel(model);
}
void everesult::on_buttonBox_clicked(QAbstractButton *button)
{
EveReprocess M_;
QModelIndex Selectedindex = ui1->listView->currentIndex();
QModelIndex StationIdsindex = ui1->listView->model()->index(0, 1);
int typeID = 0;
int stationID = 0;
stationID = ui1->listView->model()->data(StationIdsindex, Qt::DisplayRole).toInt();
typeID = ui1->listView->model()->data(Selectedindex, Qt::DisplayRole).toInt();
M_.GetMaterials(typeID, stationID);
}
--------------------------------------------------
Getmaterial and replyFinished from main window.
--------------------------------------------------
void EveReprocess::GetMaterials(int typeId, int stationid)
{
//get typeid from material list
this->modelMaterial = new QSqlQueryModel();
modelMaterial->setQuery(QString("SELECT tm.quantity, tm.materialTypeID, t.typeName FROM invTypeMaterials tm INNER JOIN invTypes t ON t.TypeID = tm.materialTypeId WHERE tm.TypeID=%1 ").arg(typeId));
if (!modelMaterial->query().exec())
qDebug() << modelMaterial->query().lastError();
//Set eve Central Url with typeids
QUrl url = QUrl("http://api.eve-central.com/api/marketstat?");
QUrlQuery q;
int numRows = modelMaterial->rowCount();
for (int row = 0; row < numRows; ++row)
{
QModelIndex index = modelMaterial->index(row, 1);
q.addQueryItem( QString("typeid"), QString::number(modelMaterial->data(index, Qt::DisplayRole).toInt()));
}
q.addQueryItem( QString("usesystem"), QString::number(stationid));
//set created url and connect
url.setQuery(q);
qDebug() << url;
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply *)));
manager->get(QNetworkRequest(url) );
}
void EveReprocess::replyFinished(QNetworkReply *reply)
{
qDebug() << "replyFinished called";
if ( reply->error() != QNetworkReply::NoError ) {
qDebug() << "Request failed, " << reply->errorString();
emit replyFinished(false);
return;
}
qDebug() << "Request succeeded";
//process with xmlreader and get values
processSearchResult( reply);
}
some of the code is here, i think it should be somewhere here, as the rest works fine.
this issue showed up after i use a dialog to let user pick a int from a list.
below is the function that calls the dialog that i have made for this. sorry about code format wil clean it up after it is working
void EveReprocess::Search_TypeId(QString ItemName, QString SystemName)
{
QList<int> TypeIdList;
QList<int> StationIdList;
modelIds = new QStandardItemModel(10,2,this);
if !(db.isOpen()) return;
this->queryItem = new QSqlQuery;
queryItem->prepare("SELECT typeID FROM invTypes WHERE invTypes.typeName LIKE ? AND invTypes.groupID NOT IN (268,269,270)AND published= 1");
ItemName.prepend("%");
ItemName.append("%");
queryItem->bindValue(0, ItemName);
this->queryStation = new QSqlQuery;
queryStation->prepare("SELECT solarSystemID FROM mapSolarSystems WHERE mapSolarSystems.solarSystemName LIKE ?");
SystemName.prepend("%");
SystemName.append("%");
queryStation->bindValue(0, SystemName);
if(!queryStation->exec() || !queryItem->exec() )
{
qDebug() << queryItem->lastError().text();
qDebug() << queryItem->lastQuery();
qDebug() << queryStation->lastError().text();
qDebug() << queryStation->lastQuery();
}
while( queryStation->next())
{
StationIdList.append(queryStation->value(0).toInt());
}
while(queryItem->next())
{
TypeIdList.append(queryItem->value(0).toInt());
}
for (int i = 0; i < StationIdList.count(); ++i)
{
modelIds->setItem(i,1,new QStandardItem(QString::number(StationIdList.at(i))));
}
for (int i = 0; i < TypeIdList.count(); ++i)
{
modelIds->setItem(i,0,new QStandardItem(QString::number(TypeIdList.at(i))));
}
//
everesult Dialog;
Dialog.setmodel(modelIds);
Dialog.exec();
}
Before you proceed any further, some of your code is allows SQL injections. Even when it's not a security hole, it'll still lead to bugs. Instead of using string substitution in SQL queries, you should be using bindings.
Your problem is here:
everesult Dialog;
Dialog.setmodel(modelIds);
Dialog.exec();
The exec() is a blocking function - it blocks the main event loop until the dialog is dismissed. Thus the signals from the threaded network access manager never get delivered to your objects.
You should display the dialog box asynchronously, like so:
everesult * dialog = new everesult;
dialog->setModel(modelIds);
dialog->show();
connect(dialog, SIGNAL(accepted()), dialog, SLOT(deleteLater());
connect(dialog, SIGNAL(rejected()), dialog, SLOT(deleteLater());
Note that it's misleading to have type names starting with lower case and variable names starting with upper case. Qt's convention is the opposite, and it's useful to retain it unless you have a good reason to do otherwise.
DO Parameter Binding in SQL Queries
QSqlQuery query("SELECT .. WHERE tm.TypeID=:typeid");
query.bindValue(":typeid", typeId);
QSqlQueryModel model;
model.setQuery(query);
DON'T DO String Substitution in SQL Queries
setQuery(QString("SELECT ... WHERE tm.TypeID=%1 ").arg(typeId));

QSignalSpy to capture a reference argument

It is not possible to capture an argument that has been passed as reference with a QSignalSpy:
QSignalSpy spy( myObject, SIGNAL(foo(int&)));
...
int& i=spy.at(0).at(0).value<int&>();
Since a QVariant can not contain a reference member. Plain logic.
But are there other solutions to check the passed-in argument?
Since Qt 5, we can simply connect to a lambda function, which makes the use of the QSignalSpy unnecessary:
std::vector<Value> values;
QObject::connect(myObject, &MyObject::foo,
[&](const auto &value)
{ values.emplace_back(value); });
myObject.somethingCausingFoo();
ASSERT_EQ(1u, values.size());
EXPECT_EQ(expectedValue, values.at(0));
An "ugly solution" would be to hack the fairly simple QSignalSpy code in order to handle the reference passed arguments. I provide a minimal working example for int reference arguments. The only changes were made to initArgs and appendArgs functions.
Notice that with this approach you will only be able to check the value of the passed argument by reference. You will not be able to change it's value.
In the initArgs function we check if we have references by argument and we populate the shouldreinterpret list.
void initArgs(const QMetaMethod &member)
{
QList<QByteArray> params = member.parameterTypes();
for (int i = 0; i < params.count(); ++i) {
int tp = QMetaType::type(params.at(i).constData());
if (tp == QMetaType::Void)
{
qWarning("Don't know how to handle '%s', use qRegisterMetaType to register it.",
params.at(i).constData());
// Check if we have a reference by removing the & from the parameter name
QString argString(params.at(i).constData());
argString.remove("&");
tp = QMetaType::type(argString.toStdString().c_str());
if (tp != QMetaType::Void)
shouldReinterpret << true;
}
else
shouldReinterpret << false;
args << tp;
}
}
and the appendArgs function, where we reinterpret the passed by reference arguments:
void appendArgs(void **a)
{
QList<QVariant> list;
for (int i = 0; i < args.count(); ++i) {
QMetaType::Type type = static_cast<QMetaType::Type>(args.at(i));
if (shouldReinterpret.at(i))
{
switch (type)
{
case QMetaType::Int:
list << QVariant(type, &(*reinterpret_cast<int*>(a[i + 1])));
break;
// Do the same for other types
}
}
else
list << QVariant(type, a[i + 1]);
}
append(list);
}
Complete code for reference:
class MySignalSpy: public QObject, public QList<QList<QVariant> >
{
public:
MySignalSpy(QObject *obj, const char *aSignal)
{
#ifdef Q_CC_BOR
const int memberOffset = QObject::staticMetaObject.methodCount();
#else
static const int memberOffset = QObject::staticMetaObject.methodCount();
#endif
Q_ASSERT(obj);
Q_ASSERT(aSignal);
if (((aSignal[0] - '0') & 0x03) != QSIGNAL_CODE) {
qWarning("QSignalSpy: Not a valid signal, use the SIGNAL macro");
return;
}
QByteArray ba = QMetaObject::normalizedSignature(aSignal + 1);
const QMetaObject *mo = obj->metaObject();
int sigIndex = mo->indexOfMethod(ba.constData());
if (sigIndex < 0) {
qWarning("QSignalSpy: No such signal: '%s'", ba.constData());
return;
}
if (!QMetaObject::connect(obj, sigIndex, this, memberOffset,
Qt::DirectConnection, 0)) {
qWarning("QSignalSpy: QMetaObject::connect returned false. Unable to connect.");
return;
}
sig = ba;
initArgs(mo->method(sigIndex));
}
inline bool isValid() const { return !sig.isEmpty(); }
inline QByteArray signal() const { return sig; }
int qt_metacall(QMetaObject::Call call, int methodId, void **a)
{
methodId = QObject::qt_metacall(call, methodId, a);
if (methodId < 0)
return methodId;
if (call == QMetaObject::InvokeMetaMethod) {
if (methodId == 0) {
appendArgs(a);
}
--methodId;
}
return methodId;
}
private:
void initArgs(const QMetaMethod &member)
{
QList<QByteArray> params = member.parameterTypes();
for (int i = 0; i < params.count(); ++i) {
int tp = QMetaType::type(params.at(i).constData());
if (tp == QMetaType::Void)
{
qWarning("Don't know how to handle '%s', use qRegisterMetaType to register it.",
params.at(i).constData());
QString argString(params.at(i).constData());
argString.remove("&");
tp = QMetaType::type(argString.toStdString().c_str());
if (tp != QMetaType::Void)
shouldReinterpret << true;
}
else
shouldReinterpret << false;
args << tp;
}
}
void appendArgs(void **a)
{
QList<QVariant> list;
for (int i = 0; i < args.count(); ++i) {
QMetaType::Type type = static_cast<QMetaType::Type>(args.at(i));
if (shouldReinterpret.at(i))
{
switch (type)
{
case QMetaType::Int:
int k = (*reinterpret_cast<int*>(a[i + 1]));
list << QVariant(type, &k);
break;
}
}
else
list << QVariant(type, a[i + 1]);
}
append(list);
}
// the full, normalized signal name
QByteArray sig;
// holds the QMetaType types for the argument list of the signal
QList<int> args;
// Holds the indexes of the arguments that
QList<bool> shouldReinterpret;
};

error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'Car' (or there is no acceptable conversion)

Queue class
#ifndef Queue_H
#define Queue_H
#include "Car.h"
#include <iostream>
#include <string>
using namespace std;
const int Q_MAX_SIZE = 20;
class Queue {
private:
int size; // size of the queue
Car carQueue[Q_MAX_SIZE];
int front, rear;
public:
Queue();
~Queue();
bool isEmpty();
bool isFull();
void enqueue(Car c);
void dequeue(); // just dequeue the last car in the queue
void dequeue(Car c); // if a certain car wants to go out of the queue midway.
// Condition: Car is not in washing. Meaning is not the 1st item in the queue
void dequeue(int index); // same as the previous comment
Car getFront();
void getCarQueue(Queue);
int length();
Car get(int);
};
Queue::Queue() {
size = 0;
front = 0;
rear = Q_MAX_SIZE -1;
}
Queue::~Queue() {
while(!isEmpty()) {
dequeue();
}
}
void Queue::enqueue(Car c) {
if (!isFull()) {
rear = (rear + 1) % Q_MAX_SIZE; // circular array
carQueue[rear] = c;
size++;
} else {
cout << "Queue is currently full.\n";
}
}
void Queue::dequeue() {
}
void Queue::dequeue(int index) {
if(!isEmpty()) {
front = (front + 1) % Q_MAX_SIZE;
if(front != index) {
carQueue[index-1] = carQueue[index];
rear--;
size--;
} else {
cout << "Not allowed to dequeue the first car in the queue.\n";
}
} else {
cout << "There are no cars to dequeue.\n";
}
}
bool Queue::isEmpty() {
return size == 0;
}
bool Queue::isFull() {
return (size == Q_MAX_SIZE);
}
Car Queue::getFront() {
return carQueue[front];
}
int Queue::length() {
return size;
}
Car Queue::get(int index) {
return carQueue[index-1];
}
void Queue::getCarQueue(Queue q) {
for(int i = 0; i< q.length(); i++)
cout << q.get(i) << endl; // Error here
}
#endif
error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'Car' (or there is no acceptable conversion)
I get this error which is kind of odd. so is there anything wrong? Thanks!
cout has no idea how to process a car object; it has never seen a car object and doesn't know how you output a car as text. cout can only process types it knows about, string, char, int, etc. The specific error is because there is version of operator << that takes an ostream and a car.
There are two options:
Creation an overload for operator<< that takes an ostream and a car. That will show cout how to output a car. This isn't usually done becuase there is usually more than one way your would want to display a car.
Write the output statement so that it manually prints out car properties like
cout << c.getMake() << " " << c.getModel()

Resources