31 #include <QJsonDocument> 32 #include <QJsonObject> 34 #include <QHashIterator> 42 QAbstractTableModel(parent)
54 qmlRegisterType<ZTableModel>
55 (
"org.zuble.qml", 1, 0,
"ZTableModel");
66 const QModelIndex & parent)
const 82 const QModelIndex & parent)
const 94 const QModelIndex & index,
101 if(index.column() < 0 ||
106 qDebug() <<
"ZTableModel::data - Warning out of bounds: " << index.row() <<
", " << index.column();
155 QList<QByteArray> names =
roleNames().values();
157 QByteArray nextValue;
159 qDebug(
"dumping model role names");
161 for(
int i=0; i<names.length();i++)
163 nextValue = names.at(i);
164 qDebug(
"name=%s",nextValue.constData());
186 QVector<int> modifiedRole;
187 modifiedRole.append(role);
188 QModelIndex index = createIndex(row, 0);
190 emit dataChanged(index, index, modifiedRole);
197 QVariant valueCopy(value);
199 QMetaObject::invokeMethod(
this,
"putValue",
200 Qt::BlockingQueuedConnection,
203 Q_ARG(QVariant, valueCopy)
224 QVector<int> modifiedRole;
225 modifiedRole.append(role);
226 QModelIndex index = createIndex(row, column);
228 emit dataChanged(index, index, modifiedRole);
235 QVariant valueCopy(value);
237 QMetaObject::invokeMethod(
this,
"putValue",
238 Qt::BlockingQueuedConnection,
242 Q_ARG(QVariant, valueCopy)
271 QMetaObject::invokeMethod(
this,
"appendRow",
272 Qt::QueuedConnection,
273 Q_ARG( QVariant, data ) );
298 QMetaObject::invokeMethod(
this,
"appendRows",
299 Qt::QueuedConnection,
300 Q_ARG( QVariant, data ) );
315 beginInsertRows(QModelIndex(), insertIndex, insertIndex);
323 QMetaObject::invokeMethod(
this,
"appendRow",
324 Qt::QueuedConnection,
334 int insertIndex = -1;
342 beginInsertRows(QModelIndex(), insertIndex, insertIndex);
350 QMetaObject::invokeMethod(
this,
"appendRowIndex",
351 Qt::BlockingQueuedConnection,
352 Q_RETURN_ARG(
int, insertIndex),
368 beginInsertRows(QModelIndex(), insertIndex, insertIndex+roleRowList.count()-1);
376 QMetaObject::invokeMethod(
this,
"appendRows",
377 Qt::QueuedConnection,
387 const QString& keyText,
406 QMetaObject::invokeMethod(
this,
"appendMissingRow",
407 Qt::QueuedConnection,
408 Q_ARG(QVariant, roleRow),
409 Q_ARG(
const QString&, keyText),
410 Q_ARG(
int, keyColumn));
419 const QString& keyText,
430 0, keyText, keyColumn,
true,
true,
true);
437 QVariant row = QVariant::fromValue<ZRoleRow>(roleRow);
439 QMetaObject::invokeMethod(
this,
"appendMissingRow",
440 Qt::QueuedConnection,
441 Q_ARG(QVariant, row),
442 Q_ARG(
const QString&, keyText),
443 Q_ARG(
int, keyColumn));
476 QMetaObject::invokeMethod(
this,
"prependRow",
477 Qt::QueuedConnection,
478 Q_ARG( QVariant, data ) );
503 QMetaObject::invokeMethod(
this,
"prependRows",
504 Qt::QueuedConnection,
505 Q_ARG( QVariant, data ) );
520 beginInsertRows(QModelIndex(), 0, 0);
528 QMetaObject::invokeMethod(
this,
"prependRow",
529 Qt::QueuedConnection,
545 beginInsertRows(QModelIndex(), 0, roleRowList.count()-1);
553 QMetaObject::invokeMethod(
this,
"prependRows",
554 Qt::QueuedConnection,
581 beginRemoveRows(QModelIndex(), row, row+count-1);
595 QMetaObject::invokeMethod(
this,
"removeRows",
596 Qt::QueuedConnection,
598 Q_ARG(
int, count ) );
612 int removeCount = modelCount -
rowCount;
620 int firstRow = modelCount - removeCount;
623 removeCount = removeCount + firstRow;
633 QMetaObject::invokeMethod(
this,
"truncate",
634 Qt::QueuedConnection,
635 Q_ARG(
int, rowCount ),
636 Q_ARG(
bool, removeFromFront ) );
654 QMetaObject::invokeMethod(
this,
"copyColumn",
655 Qt::BlockingQueuedConnection,
656 Q_RETURN_ARG(
bool, status),
657 Q_ARG(
int, fromColumn ),
658 Q_ARG(
int, toColumn ));
673 const QList<int>
roles,
683 const int cellCount = cells.count();
688 const int stopIndex = startIndex + (roleCount*
columnCount);
690 if(stopIndex > cellCount)
691 throw ZblException(
"Insufficient cells to coalesce a row.");
693 for(
int i=startIndex, r=0; i<stopIndex; i++)
695 roleRow[roles.at(r++)].push_back(cells.at(i));
701 nextIndex = stopIndex;
709 const QList<int>
roles)
718 const int cellCount = cells.count();
731 roleRowList.append(
coalesceCellRow(cells, nextIndex, columnCount, roles, nextIndex));
747 QMetaObject::invokeMethod(
this,
"appendCells",
748 Qt::QueuedConnection,
749 Q_ARG( QVariant, data ),
750 Q_ARG(
bool, truncateModel));
767 QMetaObject::invokeMethod(
this,
"prependCells",
768 Qt::QueuedConnection,
769 Q_ARG( QVariant, data ),
770 Q_ARG(
bool, truncateModel));
786 const int cellCount = cellData.count();
791 throw ZblException(
"Invalid role count - data model must " 792 "contain at least one role.");
796 const int rowCount = cellCount / (roleCount*colCount);
799 throw ZblException(
"Invalid cell count - data cell count must " 800 "be at least 1 row of cells, " 801 "ie: roleCount * columnCount.");
803 const int remainderCells = cellCount % (roleCount*colCount);
806 throw ZblException(
"Invalid cell count - data cell count must " 807 "be modulo (roleCount * columnCount), " 808 "ie: an integral number of rows.");
832 else if(data.canConvert(QMetaType::QString))
834 QString oneCell = data.toString();
837 throw ZblException(
"Models with multiple roles or columns require " 838 "more than one cell to fill a row." 839 " Pass a string array containing (roleCount" 840 " * columnCount * rowCount) number of strings.");
845 dataRow.append(oneCell);
849 roleRow.insert(roleList.at(0), dataRow);
859 if(truncateModel && (startingRowCount!=0))
861 zDebug() <<
"Truncating to row count: " << startingRowCount;
862 zDebug() <<
"Truncating front: " << front;
879 QMetaObject::invokeMethod(const_cast<ZTableModel*>(
this),
"modelRowCount",
880 Qt::BlockingQueuedConnection,
881 Q_RETURN_ARG(
int, count));
901 QMetaObject::invokeMethod(const_cast<ZTableModel*>(
this),
"modelColumnCount",
902 Qt::BlockingQueuedConnection,
903 Q_RETURN_ARG(
int, count));
916 QCoreApplication::sendPostedEvents(
this);
920 QMetaObject::invokeMethod(
this,
"sync",
921 Qt::BlockingQueuedConnection);
937 QMetaObject::invokeMethod(
this,
"setColumnCount",
938 Qt::BlockingQueuedConnection,
958 QMetaObject::invokeMethod(
this,
"addRole",
959 Qt::BlockingQueuedConnection,
960 Q_RETURN_ARG(
bool, status),
961 Q_ARG(
int,roleNumber));
980 QMetaObject::invokeMethod(
this,
"addRole",
981 Qt::BlockingQueuedConnection,
982 Q_RETURN_ARG(
bool, status),
983 Q_ARG(
int, roleNumber),
984 Q_ARG(
const QString&, roleName));
1003 QMetaObject::invokeMethod(const_cast<ZTableModel*>(
this),
"getRoleCount",
1004 Qt::BlockingQueuedConnection,
1005 Q_RETURN_ARG(
int, count));
1014 QList<int> roleList;
1024 QMetaObject::invokeMethod(const_cast<ZTableModel*>(
this),
"roles",
1025 Qt::BlockingQueuedConnection,
1026 Q_RETURN_ARG(QList<int>, roleList));
1041 QHash<int, QByteArray> hash =
roleNames();
1043 QList<int> keys = hash.keys();
1045 const int keyCount = keys.size();
1047 for(
int i=0; i<keyCount; i++)
1049 const int nextRole = keys.at(i);
1051 map.insert(QString::fromUtf8(hash.value(nextRole)), QVariant(nextRole));
1057 QMetaObject::invokeMethod(const_cast<ZTableModel*>(
this),
"roleMap",
1058 Qt::BlockingQueuedConnection,
1059 Q_RETURN_ARG(QVariantMap, map));
1085 QMetaObject::invokeMethod(const_cast<ZTableModel*>(
this),
"getValue",
1086 Qt::BlockingQueuedConnection,
1087 Q_RETURN_ARG(QVariant, value),
1111 QMetaObject::invokeMethod(const_cast<ZTableModel*>(
this),
"getValue",
1112 Qt::BlockingQueuedConnection,
1113 Q_RETURN_ARG(QVariant, value),
1139 QMetaObject::invokeMethod(const_cast<ZTableModel*>(
this),
"getTableColumnRows",
1140 Qt::BlockingQueuedConnection,
1141 Q_RETURN_ARG(QVariant, value),
1142 Q_ARG(QList<int> ,roles),
1143 Q_ARG(
int,startRow),
1145 Q_ARG(
int,rowCount));
1192 Qt::ConnectionType connectType = asynchronous ? Qt::QueuedConnection : Qt::BlockingQueuedConnection;
1194 QMetaObject::invokeMethod(const_cast<ZTableModel*>(
this),
"putTableColumnRows",
1196 Q_ARG(QVariant, rows),
1197 Q_ARG(
int, startRow),
1206 const QString& text,
1209 bool forwardDirection,
1210 bool keySearch)
const 1219 startRow, text, column, caseSensitive,
1220 forwardDirection, keySearch );
1224 QMetaObject::invokeMethod(const_cast<ZTableModel*>(
this),
"findNextItemRow",
1225 Qt::BlockingQueuedConnection,
1226 Q_RETURN_ARG(
int, foundRow),
1227 Q_ARG(
int, startRow),
1228 Q_ARG(
const QString&,text),
1230 Q_ARG(
bool, caseSensitive),
1231 Q_ARG(
bool, forwardDirection),
1232 Q_ARG(
bool, keySearch));
1257 QJsonValue roleValue = data.value(
"roles");
1259 if(roleValue.isUndefined())
1260 throw ZblException(
"JSON object is missing \"roles\" value.");
1262 if(!roleValue.isObject())
1263 throw ZblException(
"JSON object \"roles\" value should be an object of number/name pairs.");
1265 QJsonValue dataValue = data.value(
"data-rows");
1267 if(dataValue.isUndefined())
1268 throw ZblException(
"JSON object is missing \"data-rows\" value.");
1270 if(!dataValue.isArray())
1271 throw ZblException(
"JSON object \"data-rows\" value should be an array of row arrays.");
1275 jRoles = roleValue.toObject();
1278 jData = dataValue.toArray();
1280 QStringList roleKeys = jRoles.keys();
1287 QString strNextRoleKey = roleKeys.at(i);
1288 int nextRoleKey = strNextRoleKey.toInt();
1290 QJsonValue nextRoleValue(jRoles.value(strNextRoleKey));
1292 m_model.
addRole(nextRoleKey, nextRoleValue.toVariant().toByteArray());
1295 const int rowCount = jData.count();
1299 QJsonValue nextRowValue = jData.at(j);
1301 if(!nextRowValue.isArray())
1303 zWarning() <<
"WARNING: Invalid data: data rows array should " 1304 "contain only arrays of data cells.";
1307 QJsonArray jNextRow = nextRowValue.toArray();
1309 QVariantList nextRowList = jNextRow.toVariantList();
1315 QVariant nextDataValue = nextRowList.at(k);
1317 QString strNextRoleKey = roleKeys.at(k);
1319 int nextRoleKey = strNextRoleKey.toInt();
1323 QVariantList nextRowCell;
1324 nextRowCell.append(nextDataValue);
1326 roleRow.insert(nextRoleKey,nextRowCell);
1335 QMetaObject::invokeMethod(
this,
"putJsonData",
1336 Qt::BlockingQueuedConnection,
1337 Q_ARG(QJsonObject, data));
1360 QJsonObject modelObject;
1366 QHashIterator<int, QByteArray> it(roles);
1372 jRoles.insert(QString::number(it.key()),
1373 QJsonValue(QString::fromLatin1(it.value())));
1379 QStringList roleKeys = jRoles.keys();
1382 for(
int r=0; r<rows; r++)
1388 QString roleKey = roleKeys.at(v);
1390 QJsonValue roleValue = jRoles.value(roleKey);
1392 QJsonValue::Type valueType = roleValue.type();
1394 QString strRoleValue = roleValue.toString();
1396 int nextRole = roleKey.toInt();
1398 rowData.append(QJsonValue::fromVariant(
1402 jData.append(rowData);
1406 modelObject.insert(
"roles", QJsonValue(jRoles));
1407 modelObject.insert(
"data-rows", QJsonValue(jData));
1412 QMetaObject::invokeMethod(const_cast<ZTableModel*>(
this),
"getJsonData",
1413 Qt::BlockingQueuedConnection,
1414 Q_RETURN_ARG(QJsonObject, modelObject));
1427 throw ZblException(
"Invalid argument: targetThread is NULL!");
1429 if(this->thread() != targetThread)
1433 moveToThread(targetThread);
1437 QMetaObject::invokeMethod(
this,
"moveModelToThread",
1438 Qt::BlockingQueuedConnection,
1439 Q_ARG(QThread*, targetThread));
1460 QMetaObject::invokeMethod(
this,
"invalidateModel",
1461 Qt::BlockingQueuedConnection
void dumpModelData(const ZblTableCell *cell=NULL) const
Prints diagnostic information about the state of the contained data to debug output.
void tableModified(int dataRole, int rowNumber)
Sent when a table cell has been modified.
Q_INVOKABLE void appendMissingRow(ZRoleRow roleRow, const QString &keyText, int keyColumn=0)
Appends the specified row if no rows contain the specified text in the specified column. Otherwise does nothing.
bool copyColumn(int fromColumn, int toColumn, ZblTableCell *cell=NULL)
Copies data between data model columns for all rows and roles in the model.
Q_INVOKABLE void prependCells(QVariant data, bool truncateModel=false)
Asynchronously converts an array of cell data into one or more rows of model data and prepends it to ...
int findNextItemRow(int startRow, const QString &text, int column=0, bool caseSensitive=true, bool forwardDirection=true, bool keySearch=false, const ZblTableCell *cell=NULL) const
Searches for the specified text from startIndex.
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
QAbstractTableModel override.
void setColumnCount(int count, ZblTableCell *cell=NULL)
Sets the number of columns in the data table. This method fails if the data table contains rows...
Q_INVOKABLE void appendCells(QVariant data, bool truncateModel=false)
Asynchronously converts an array of cell data into one or more rows of model data and appends it to t...
void prependRows(QList< QMap< int, QList< QVariant > > > data, ZblTableCell *cell=NULL)
virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
QAbstractTableModel override.
Q_INVOKABLE void clearData()
Removes all data from the model. Roles and role names remain intact.
int getUserRole()
Returns the value of Qt::UserRole. ie: the first role number available for user defined roles...
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const
QAbstractTableModel override.
Q_INVOKABLE int appendRowIndex(ZRoleRow roleRow)
void moveModelToThread(QThread *targetThread)
Q_INVOKABLE QJsonObject getJsonData() const
Copies data from the table model into a newly created JSON object and returns it. ...
void clearData(ZblTableCell *cell=NULL)
Removes all data rows from the specified table cell.
Q_INVOKABLE void putValue(int role, int row, const QVariant &value)
Sets the value of the specified cell in the data set.
Q_INVOKABLE void prependRow(QVariant data)
int getRoleCount() const
Returns the number of roles defined for this model.
Q_INVOKABLE void truncate(int rowCount, bool removeFromFront=false)
Q_INVOKABLE QVariantMap roleMap() const
Determines which roles are in the data set. This method may block the current thread.
#define ZBL_REGISTER_LOGGED_OBJECT
void invalidateModel()
Resets the model.
Q_INVOKABLE void dumpModelData() const
dumps diagnostic information about the model to the debug output.
void setData(int role, int row, int col, const QVariant &value, ZblTableCell *cell=NULL)
int rowCount(const ZblTableCell *cell=NULL) const
ZRoleRowList coalesceCellRows(const ZDataRow cells, int columnCount, const QList< int > roles)
Q_INVOKABLE QList< int > roles() const
Determines which roles are in the data set. This method may block the current thread.
Q_INVOKABLE QVariant getValue(int role, int row)
Obtains the value of the specified data cell.
void prependRow(QMap< int, QList< QVariant > > data, ZblTableCell *cell=NULL)
Q_INVOKABLE int findNextItemRow(int startRow, const QString &text, int column=0, bool caseSensitive=true, bool forwardDirection=true, bool keySearch=false) const
Searches for the specified text from startIndex.
Q_INVOKABLE void appendRows(QVariant data)
QMap< int, QList< QVariant > > ZRoleRow
Represents a single row (or column for column headers) of data cell values for multiple roles...
#define ZBL_SLOT_BEGIN_TRY
static void registerType()
Registers ZTableModel as a QML type.
#define ZBL_DEFINE_LOGGED_OBJECT(class_name)
This two dimensional table model is used to store and manipulate data.
#define ZBL_SLOT_END_VOID(facility, code, error_message)
Q_INVOKABLE void clearRoles()
Removes all roles, role names and data from the model.
void putTableColumnRows(QVariant rows, int startRow, int col, ZblTableCell *cell=NULL)
Q_INVOKABLE void putJsonData(QJsonObject data)
Writes data from the specified JSON object into the data table. Previous contents of the data table a...
void clearRoles()
Removes all information from the model and returns the model to it's uninitialized state...
Q_INVOKABLE bool copyColumn(int fromColumn, int toColumn)
ZRoleRow coalesceCellRow(const ZDataRow cells, int startIndex, int columnCount, const QList< int > roles, int &nextIndex)
Q_INVOKABLE void setColumnCount(int count)
Sets the number of columns the table will contain. This method may block the current thread...
bool inObjectThread(const QObject &object)
Q_INVOKABLE int modelRowCount() const
Returns the number of rows in the data set. This method may block the current thread.
void appendRows(QList< QMap< int, QList< QVariant > > > data, ZblTableCell *cell=NULL)
Q_INVOKABLE QVariant getTableColumnRows(QList< int > roles, int startRow, int col, int rowCount)
Obtain data values for a set of rows from a single model column.
Q_INVOKABLE void putTableColumnRows(QVariant rows, int startRow, int col)
Replaces the current value for a set of rows for a single model column.
Q_INVOKABLE void mergeCells(QVariant data, bool front=true, bool truncateModel=true)
Converts an array of cell data into one or more rows of model data and either appends or prepends it ...
int roleCount(const ZblTableCell *cell=NULL) const
Obtains the number of roles contained by the specified cell.
Zuble's Qt Exception Object.
bool addRole(int roleNumber, ZblTableCell *cell=NULL)
Adds the specified role to the data table.
QList< int > roles(const ZblTableCell *cell=NULL) const
Determines which roles are in the data set.
int roleCount
Returns the number of roles defined for this model.
static void registerLogCategory()
Q_INVOKABLE bool addRole(int roleNumber)
Adds the specified role to the data model. This method may block the current thread.
Q_INVOKABLE void sync()
Blocks thread until model's event queue has been processed.
QList< QMap< int, QList< QVariant > > > ZRoleRowList
Represents multiple rows of data cell values for multiple roles for multiple columns.
Q_INVOKABLE void sendTableColumnRows(QVariant rows, int startRow, int col)
Asynchronously replaces the current value for a set of rows for a single model column.
void insertTableColumnRows(QVariant rows, int startRow, int col, bool asynchronous)
Q_INVOKABLE void removeRows(int row, int count)
Q_INVOKABLE void removeRow(int row)
void appendRow(QMap< int, QList< QVariant > > data, ZblTableCell *cell=NULL)
virtual QHash< int, QByteArray > roleNames() const
QAbstractTableModel override.
#define ZBL_SLOT_END_RETURN(return_success, return_failed, facility, code, error_message)
zRoleNames roleNames() const
Obtains a hash that maps role numbers to role names.
QList< QVariant > ZDataRow
Represents a single row (or column for column headers) of data cell values for a single role...
void removeRows(int row, int count, ZblTableCell *cell=NULL)
Removes the specified data rows from the model.
int columnCount(const ZblTableCell *cell=NULL) const
Q_INVOKABLE void appendRow(QVariant data)
QVariant getTableColumnRows(QList< int > roles, int startRow, int col, int rowCount, ZblTableCell *cell=NULL) const
Q_INVOKABLE void prependRows(QVariant data)
Q_INVOKABLE int modelColumnCount() const
Returns the number of columns in the data set. This method may block the current thread.
QVariant data(int role, int row, int col, const ZblTableCell *cell=NULL) const