[rkward-cvs] SF.net SVN: rkward:[4396] trunk/rkward/rkward/plugin

tfry at users.sourceforge.net tfry at users.sourceforge.net
Tue Oct 30 12:09:07 UTC 2012


Revision: 4396
          http://rkward.svn.sourceforge.net/rkward/?rev=4396&view=rev
Author:   tfry
Date:     2012-10-30 12:09:06 +0000 (Tue, 30 Oct 2012)
Log Message:
-----------
Matrix input element mostly finished (in theory)

Modified Paths:
--------------
    trunk/rkward/rkward/plugin/rkmatrixinput.cpp
    trunk/rkward/rkward/plugin/rkmatrixinput.h

Modified: trunk/rkward/rkward/plugin/rkmatrixinput.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkmatrixinput.cpp	2012-10-27 13:50:50 UTC (rev 4395)
+++ trunk/rkward/rkward/plugin/rkmatrixinput.cpp	2012-10-30 12:09:06 UTC (rev 4396)
@@ -67,8 +67,8 @@
 	column_count->setInternal (true);
 	addChild (column_count);
 	addChild (tsv_data);
-	connect (row_count, SIGNAL (valueChanged(RKComponentPropertyBase*)), this, SLOT (dimensionPropertyChanged()));
-	connect (column_count, SIGNAL (valueChanged(RKComponentPropertyBase*)), this, SLOT (dimensionPropertyChanged()));
+	connect (row_count, SIGNAL (valueChanged(RKComponentPropertyBase*)), this, SLOT (dimensionPropertyChanged(RKComponentPropertyBase*)));
+	connect (column_count, SIGNAL (valueChanged(RKComponentPropertyBase*)), this, SLOT (dimensionPropertyChanged(RKComponentPropertyBase*)));
 	connect (tsv_data, SIGNAL (valueChanged(RKComponentPropertyBase*)), this, SLOT (tsvPropertyChanged()));
 	updating_tsv_data = false;
 	updating_dimensions = false;
@@ -97,16 +97,17 @@
 	int row = index.row ();
 	int column = index.column ();
 
+	// handle trailing rows / cols in user expandable tables
 	bool trailing = false;
 	if (row > row_count->intValue ()) {
-		if ((!allow_user_resize_rows) || (row > row_count->intValue () + TRAILING_ROWS)) {
+		if ((!allow_user_resize_rows) || (row > row_count->intValue () + trailing_rows)) {
 			RK_ASSERT (false);
 			return QVariant ();
 		}
 		trailing = true;
 	}
 	if (column > column_count->intValue ()) {
-		if ((!allow_user_resize_columns) || (column > column_count->intValue () + TRAILING_COLS)) {
+		if ((!allow_user_resize_columns) || (column > column_count->intValue () + trailing_columns)) {
 			RK_ASSERT (false);
 			return QVariant ();
 		}
@@ -117,10 +118,232 @@
 		if (role == Qt::ToolTipRole || role == Qt::StatusTipRole) return QVariant (i18n ("Type on these cells to expand the table"));
 		return QVariant ();
 	}
-#error TODO
+
+	// regular cells
+	QString value;
+	if (columns.size () > column) {	// column >= columns.size() can happen, legally. In this case the value is simply missing.
+		value = columns[column].storage.value (row);
+	}
+	if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) {
+		return QVariant (value);
+	} else if (role == Qt::BackgroundRole) {
+		if (!is_valid && (value.isEmpty () && !allow_missings) || !isValueValid (value)) return QVariant (QBrush (Qt::red));
+	} else if ((role == Qt::ToolTipRole) || (role == Qt::StatusTipRole)) {
+		if (!is_valid && (value.isEmpty () && !allow_missings)) return QVariant (i18n ("Empty values are not allowed"));
+		if (!is_valid && !isValueValid (value)) return QVariant (i18n ("This value is not allowed, here"));
+	}
+	return QVariant ();
 }
 
+bool RKMatrixInput::setData (const QModelIndex& index, const QVariant& value, int role) {
+	RK_TRACE (PLUGIN);
 
+	if (!index.isValid ()) return false;
+	if (role != Qt::EditRole) return false;
+	setCellValue (index.row (), index.column (), value.toString ());
+	return true;
+}
+
+bool RKMatrixInput::expandStorageForColumn (int column) {
+	RK_TRACE (PLUGIN);
+
+	if ((column < 0) || (column >= (column_count->intValue () + trailing_columns))) {
+		RK_ASSERT (false);
+		return false;
+	}
+
+	while (column >= columns.size ()) {
+		Column col;
+		col.valid_up_to_row = -1;
+		col.filled_up_to_row = -1;
+		columns.append (col);
+	}
+	return true;
+}
+
+void RKMatrixInput::setCellValue (int row, int column, const QString& value) {
+	RK_TRACE (PLUGIN);
+
+	if ((!expandStorageForColumn (column)) || (row < 0) || (row >= (row_count->intValue () + trailing_rows))) {
+		RK_ASSERT (false);
+		return;
+	}
+
+	Column &col = columns[col];
+	while (row >= col.storage.size ()) {
+		col.storage.append (QString ());
+	}
+	col.storage[row] = value;
+	updateColumn (row, column);
+}
+
+void RKMatrixInput::setColumnValue (int column, const QString& value) {
+	RK_TRACE (PLUGIN);
+
+	if (!expandStorageForColumn (column)) return;
+	columns[column].storage = value.split ('\t', QString::KeepEmptyParts);
+	updateColumn (0, column);
+}
+
+void RKMatrixInput::updateColumn (int offset, int column) {
+	RK_TRACE (PLUGIN);
+	RK_ASSERT ((column >= 0) && (column < columns.size ()));
+
+	Column &col = columns[column];
+
+	// check for trailing empty rows:
+	int last_row = col.storage.size () - 1;
+	while ((last_row >= 0) && col.storage[last_row].isEmpty ()) {
+		--last_row;
+	}
+	col.filled_up_to_row = last_row;
+
+	offset = qMax (0, qMin (offset, col.valid_up_to_row));
+	while (offset < col.storage.size ()) {
+		if (!isValueValid (col.storage[offset])) break;
+		offset++;
+	}
+	col.valid_up_to_row = offset - 1;
+	col.cached_tab_joined_string.clear (); // == no valid cache
+
+	updateDataAndDimensions ();
+	updateValidityFlag ();
+}
+
+void RKMatrixInput::updateValidityFlag () {
+	RK_TRACE (PLUGIN);
+
+	for (int i = 0; i < column_count->intValue (); ++i) {
+		if (i >= columns.size ()) {	// hit end of data, before hitting any invalid strings
+			is_valid = allow_missings;
+			return;
+		}
+
+		Column &col = columns[i];
+		if (col.valid_up_to_row >= (row_count->intValue () - 1)) continue;
+		else if (allow_missings && (col.valid_up_to_row >= (col.storage.size () - 1))) continue;
+		else {
+			is_valid = false;
+			return;
+		}
+	}
+	is_valid = true;
+}
+
+void RKMatrixInput::updateDataAndDimensions () {
+	RK_TRACE (PLUGIN);
+
+	if (updating_tsv_data) return;
+	updating_tsv_data = true;
+
+	int max_row = row_count->intValue () - 1;
+	if (allow_user_resize_rows) {
+		max_row = -1;
+		for (int i = columns.size () - 1; i >= 0; --i) {
+			max_row = qMax (max_row, columns[i].filled_up_to_row);
+		}
+		if (max_row != row_count->intValue () - 1) {
+			updating_dimensions = true;
+			row_count->setIntValue (max_row);
+			updating_dimensions = false;
+		}
+	}
+
+	int max_col = column_count->intValue () - 1;
+	if (allow_user_resize_columns) {
+		for (max_col = columns.size () - 1; max_col >= 0; --max_col) {
+			if (columns[max_col].filled_up_to_row < 0) {
+				columns.pop_back ();
+			} else {
+				break;
+			}
+		}
+		if (max_col != column_count->intValue () - 1) {
+			updating_dimensions = true;
+			column_count->setIntValue (max_col);
+			updating_dimensions = false;
+		}
+	}
+
+	QStringList tsv;
+	QString empty_column (max_row, '\t');	// NOTE: *Not* max_row+1, as the number of seps is rows - 1
+	for (int i = 0; i < max_col; ++i) {
+		if (i > (columns.size () - 1)) {
+			tsv.append (empty_column);
+		} else {
+			Column& col = columns[i];
+			if (col.cached_tab_joined_string.isNull ()) {
+				QString cache = col.storage.mid (0, max_row + 1).join ('\t');
+				if (col.storage.size () < max_row) {
+					QString empty_trail (max_row - col.storage.size (), '\t');
+					cache.append (empty_trail);
+				}
+				col.cached_tab_joined_string = cache;
+			}
+			tsv.append (col.cached_tab_joined_string);
+		}
+	}
+	tsv_data->setValue (tsv);
+
+	updating_tsv_data = false;
+}
+
+void RKMatrixInput::dimensionPropertyChanged (RKComponentPropertyBase *property) {
+	RK_TRACE (PLUGIN);
+
+	if (updating_dimensions) return;
+	if (allow_user_resize_rows && (property == row_count)) {
+		RK_ASSERT (false);
+		return;
+	}
+	if (allow_user_resize_columns && (property == column_count)) {
+		RK_ASSERT (false);
+		return;
+	}
+
+	if (property == row_count) {		// invalidates column caches
+		for (int i = columns.size () - 1; i >= 0; --i) {
+			columns[i].cached_tab_joined_string.clear ();
+		}
+	}
+
+	updateValidityFlag ();
+	updateDataAndDimensions ();
+}
+
+void RKMatrixInput::tsvPropertyChanged () {
+	RK_TRACE (PLUGIN);
+
+	bool old_updating_tsv_data = updating_tsv_data;
+	updating_tsv_data = true;
+
+	columns.clear ();
+	QStringList coldata = tsv_data->value ().split ('\n', QString::KeepEmptyParts);
+	for (int i = 0; i < coldata.size (); ++i) {
+		setColumnValue (i, coldata[i]);
+	}
+
+	updating_tsv_data = old_updating_tsv_data;
+	updateDataAndDimensions ();
+}
+
+bool RKMatrixInput::isValueValid (const QString& value) const {
+	if (mode == String) return true;
+	if (value.isEmpty ()) return allow_missings;
+
+	bool number_ok;
+	double val;
+	if (mode == Integer) {
+		val = value.toInt (&number_ok);
+	} else {
+		val = value.toDouble (&number_ok);
+	}
+	if (!number_ok) return false;
+	if (val < min) return false;
+	return (val < max);
+}
+
 #error TODO
+#error TODO signal model layout and data changes
 
 #include "rkmatrixinput.moc"

Modified: trunk/rkward/rkward/plugin/rkmatrixinput.h
===================================================================
--- trunk/rkward/rkward/plugin/rkmatrixinput.h	2012-10-27 13:50:50 UTC (rev 4395)
+++ trunk/rkward/rkward/plugin/rkmatrixinput.h	2012-10-30 12:09:06 UTC (rev 4396)
@@ -22,6 +22,7 @@
 
 #include <QAbstractTableModel>
 #include <QDomElement>
+#include <QStringList>
 
 class QTableView;
 
@@ -37,7 +38,7 @@
 	bool isValid () { return is_valid; };
 	QString value (const QString &modifier);
 private slots:
-	void dimensionPropertyChanged ();
+	void dimensionPropertyChanged (RKComponentPropertyBase *property);
 	void tsvPropertyChanged ();
 private:
 	RKComponentPropertyInt *row_count;
@@ -66,10 +67,12 @@
 
 	bool isValueValid (const QString &value) const;
 	void updateValidityFlag ();
+	void updateDataAndDimensions ();
 
-	bool setCellValue (int row, int column, const QString& value);
-	bool setColumnValue (int column, const QString& value);
-	bool setTableValue (const QString& value);
+	void setCellValue (int row, int column, const QString& value);
+	void setColumnValue (int column, const QString& value);
+	void updateColumn (int offset, int column);
+	bool expandStorageForColumn (int column);
 
 	bool is_valid;
 
@@ -77,6 +80,7 @@
 	// lost, if a user shrinks a table, accidentally, then re-grows it.
 	struct Column {
 		int valid_up_to_row;	// to save validizing the entire table on each change, we keep track of validity per column
+		int filled_up_to_row;
 		QStringList storage;
 		QString cached_tab_joined_string;
 	};

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.





More information about the rkward-tracker mailing list