[rkward-cvs] SF.net SVN: rkward:[4403] trunk/rkward/rkward
tfry at users.sourceforge.net
tfry at users.sourceforge.net
Wed Oct 31 12:03:24 UTC 2012
Revision: 4403
http://rkward.svn.sourceforge.net/rkward/?rev=4403&view=rev
Author: tfry
Date: 2012-10-31 12:03:24 +0000 (Wed, 31 Oct 2012)
Log Message:
-----------
Tweaks to matrix input element implementation
Modified Paths:
--------------
trunk/rkward/rkward/plugin/rkmatrixinput.cpp
trunk/rkward/rkward/plugin/rkmatrixinput.h
trunk/rkward/rkward/plugins/testing/matrix1.xml
Modified: trunk/rkward/rkward/plugin/rkmatrixinput.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkmatrixinput.cpp 2012-10-31 11:12:30 UTC (rev 4402)
+++ trunk/rkward/rkward/plugin/rkmatrixinput.cpp 2012-10-31 12:03:24 UTC (rev 4403)
@@ -20,6 +20,7 @@
#include <QVBoxLayout>
#include <QLabel>
#include <QTableView>
+#include <QHeaderView>
#include "klocale.h"
@@ -55,6 +56,7 @@
max = FLT_MAX;
}
+ // Note: string type matrix allows missings, implicitly (treating them as empty strings)
allow_missings = xml->getBoolAttribute (element, "allow_missings", false, DL_INFO);
allow_user_resize_columns = xml->getBoolAttribute (element, "allow_user_resize_columns", true, DL_INFO);
allow_user_resize_rows = xml->getBoolAttribute (element, "allow_user_resize_rows", true, DL_INFO);
@@ -73,15 +75,23 @@
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;
model = new RKMatrixInputModel (this);
QString headers = xml->getStringAttribute (element, "horiz_headers", QString (), DL_INFO);
if (!headers.isEmpty ()) model->horiz_header = headers.split (';');
headers = xml->getStringAttribute (element, "vert_headers", QString (), DL_INFO);
if (!headers.isEmpty ()) model->vert_header = headers.split (';');
- updateDataAndDimensions ();
+ updateAll ();
display->setModel (model);
+ display->setAlternatingRowColors (true);
+ if (xml->getBoolAttribute (element, "fixed_width", false, DL_INFO)) {
+ int max_col = column_count->intValue () - 1;
+ display->setFixedWidth (display->verticalHeader ()->width () + display->columnViewportPosition (max_col) + display->columnWidth (max_col) + display->verticalHeader ()->fontMetrics ().width ("0"));
+ }
+ if (xml->getBoolAttribute (element, "fixed_height", false, DL_INFO)) {
+ int max_row = row_count->intValue () - 1;
+ display->setFixedHeight (display->horizontalHeader ()->height () + display->rowViewportPosition (max_row) + display->rowHeight (max_row));
+ }
}
RKMatrixInput::~RKMatrixInput () {
@@ -99,7 +109,7 @@
bool ok;
int col = modifier.toInt (&ok);
- if ((col >= 0) && ok) return makeColumnString (col, "\t");
+ if ((col >= 0) && ok) return makeColumnString (col, "\t", false);
return tsv_data->value (modifier);
}
@@ -113,8 +123,7 @@
while (column >= columns.size ()) {
Column col;
- col.valid_up_to_row = -1;
- col.filled_up_to_row = -1;
+ col.last_valid_row = -1;
columns.append (col);
}
return true;
@@ -129,11 +138,13 @@
}
Column &col = columns[column];
+ if (col.storage.value (row) == value) return;
+
while (row >= col.storage.size ()) {
col.storage.append (QString ());
}
col.storage[row] = value;
- updateColumn (row, column);
+ updateColumn (column);
model->dataChanged (model->index (row, column), model->index (row, column));
}
@@ -142,71 +153,52 @@
if (!expandStorageForColumn (column)) return;
columns[column].storage = value.split ('\t', QString::KeepEmptyParts);
- updateColumn (0, column);
+ updateColumn (column);
model->dataChanged (model->index (0, column), model->index (row_count->intValue () + trailing_rows, column));
}
-void RKMatrixInput::updateColumn (int offset, int column) {
+void RKMatrixInput::updateColumn (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;
+ int last_row = col.storage.size ();
+ while ((--last_row >= 0) && col.storage[last_row].isEmpty ()) { // strip empty trailing strings
+ col.storage.pop_back ();
}
- 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.last_valid_row = -1;
col.cached_tab_joined_string.clear (); // == no valid cache
- updateDataAndDimensions ();
+ updateAll ();
}
-void RKMatrixInput::updateValidityFlag () {
+QString RKMatrixInput::makeColumnString (int column, const QString& sep, bool r_pasteable) {
RK_TRACE (PLUGIN);
- is_valid = true;
- 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;
- break;
- }
-
- 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;
- break;
- }
- }
- changed ();
-}
-
-QString RKMatrixInput::makeColumnString (int column, const QString& sep) {
- RK_TRACE (PLUGIN);
-
QStringList storage;
if (column < columns.size ()) {
storage = columns[column].storage;
}
QString ret;
- if (!storage.isEmpty ()) ret = QStringList (storage.mid (0, row_count->intValue ())).join (sep);
- for (int i = storage.size (); i < row_count->intValue (); ++i) {
- ret.append (sep);
+ ret.reserve (3 * row_count->intValue ()); // a rather conservative estimate for most purposes
+ for (int i = 0; i < row_count->intValue (); ++i) {
+ if (i > 0) ret.append (sep);
+ const QString val = storage.value (i);
+ if (r_pasteable) {
+ if (mode == String) ret.append (RObject::rQuote (val));
+ else if (val.isEmpty ()) ret.append ("NA");
+ else ret.append (val);
+ } else {
+ ret.append (val);
+ }
}
return ret;
}
-void RKMatrixInput::updateDataAndDimensions () {
+void RKMatrixInput::updateAll () {
RK_TRACE (PLUGIN);
if (updating_tsv_data) return;
@@ -216,30 +208,22 @@
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);
+ max_row = qMax (max_row, columns[i].storage.size () - 1);
}
if (max_row != row_count->intValue () - 1) {
- updating_dimensions = true;
- model->layoutAboutToBeChanged ();
row_count->setIntValue (max_row + 1);
- model->layoutChanged ();
- 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) {
+ if (!columns[max_col].storage.isEmpty ()) {
break;
}
}
if (max_col != column_count->intValue () - 1) {
- updating_dimensions = true;
- model->layoutAboutToBeChanged ();
column_count->setIntValue (max_col + 1);
- model->layoutChanged ();
- updating_dimensions = false;
}
}
@@ -248,7 +232,7 @@
for (; i < columns.size (); ++i) {
Column& col = columns[i];
if (col.cached_tab_joined_string.isEmpty ()) {
- col.cached_tab_joined_string = makeColumnString (i, "\t");
+ col.cached_tab_joined_string = makeColumnString (i, "\t", false);
}
tsv.append (col.cached_tab_joined_string);
}
@@ -258,30 +242,41 @@
tsv_data->setValue (tsv.join ("\n"));
updating_tsv_data = false;
- updateValidityFlag ();
+
+ // finally, check whether table is valid, and signal change
+ bool new_valid = true;
+ for (int i = 0; i < column_count->intValue (); ++i) {
+ if (!isColumnValid (i)) {
+ new_valid = false;
+ break;
+ }
+ }
+ if (new_valid != is_valid) {
+ is_valid = new_valid;
+ model->headerDataChanged (Qt::Horizontal, 0, column_count->intValue () - 1);
+ }
+ changed ();
}
void RKMatrixInput::dimensionPropertyChanged (RKComponentPropertyBase *property) {
RK_TRACE (PLUGIN);
- if (updating_dimensions) return;
if (allow_user_resize_rows && (property == row_count)) {
- RK_ASSERT (false);
- return;
+ RK_ASSERT (updating_tsv_data);
}
if (allow_user_resize_columns && (property == column_count)) {
- RK_ASSERT (false);
- return;
+ RK_ASSERT (updating_tsv_data);
}
if (property == row_count) { // invalidates column caches
for (int i = columns.size () - 1; i >= 0; --i) {
+ columns[i].last_valid_row = qMin (columns[i].last_valid_row, row_count->intValue () - 1);
columns[i].cached_tab_joined_string.clear ();
}
}
model->layoutAboutToBeChanged ();
- updateDataAndDimensions ();
+ updateAll ();
model->layoutChanged ();
}
@@ -298,7 +293,7 @@
}
updating_tsv_data = false;
- updateDataAndDimensions ();
+ updateAll ();
}
bool RKMatrixInput::isValueValid (const QString& value) const {
@@ -314,11 +309,43 @@
}
if (!number_ok) return false;
if (val < min) return false;
- return (val < max);
+ return (val <= max);
}
+bool RKMatrixInput::isColumnValid (int column) {
+ if (column < 0) {
+ RK_ASSERT (false);
+ return false;
+ }
+ if (column >= columns.size ()) return (allow_missings || (row_count->intValue () == 0));
+ Column &col = columns[column];
+ if (col.last_valid_row >= (row_count->intValue () - 1)) {
+ return true;
+ } else if (allow_missings && (col.last_valid_row >= (col.storage.size () - 1))) {
+ return true;
+ } else {
+ }
+
+ int row = col.last_valid_row + 1;
+ for (; row < col.storage.size (); ++row) {
+ if (!isValueValid (col.storage[row])) {
+ col.last_valid_row = row - 1;
+ return false;
+ }
+ }
+ col.last_valid_row = row - 1;
+
+ if (col.last_valid_row < (row_count->intValue () - 1)) {
+ return allow_missings;
+ }
+ return true;
+}
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////
RKMatrixInputModel::RKMatrixInputModel (RKMatrixInput* _matrix) : QAbstractTableModel (_matrix) {
@@ -377,7 +404,7 @@
if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) {
return QVariant (value);
} else if (role == Qt::BackgroundRole) {
- if (!matrix->is_valid && !matrix->isValueValid (value)) return QVariant (QBrush (Qt::red));
+ if (!matrix->is_valid && !matrix->isValueValid (value)) return QVariant (Qt::red);
} else if ((role == Qt::ToolTipRole) || (role == Qt::StatusTipRole)) {
if (!matrix->is_valid && (value.isEmpty () && !matrix->allow_missings)) return QVariant (i18n ("Empty values are not allowed"));
if (!matrix->is_valid && !matrix->isValueValid (value)) return QVariant (i18n ("This value is not allowed, here"));
@@ -400,6 +427,11 @@
else list = &vert_header;
if (section < list->size ()) return QVariant ((*list)[section]);
return QVariant (QString::number (section + 1));
+ } else if (orientation == Qt::Horizontal) {
+ if (section < matrix->column_count->intValue ()) {
+ if ((role == Qt::BackgroundRole) && !matrix->isColumnValid (section)) return QVariant (Qt::red);
+ if (((role == Qt::ToolTipRole) || (role == Qt::StatusTipRole)) && !matrix->isColumnValid (section)) return QVariant (i18n ("This column contains illegal values in some of its cells"));
+ }
}
return QVariant ();
}
Modified: trunk/rkward/rkward/plugin/rkmatrixinput.h
===================================================================
--- trunk/rkward/rkward/plugin/rkmatrixinput.h 2012-10-31 11:12:30 UTC (rev 4402)
+++ trunk/rkward/rkward/plugin/rkmatrixinput.h 2012-10-31 12:03:24 UTC (rev 4403)
@@ -62,22 +62,21 @@
int trailing_columns;
bool isValueValid (const QString &value) const;
- void updateValidityFlag ();
- void updateDataAndDimensions ();
+ void updateAll ();
void setCellValue (int row, int column, const QString& value);
void setColumnValue (int column, const QString& value);
- void updateColumn (int offset, int column);
+ void updateColumn (int column);
bool expandStorageForColumn (int column);
- QString makeColumnString (int column, const QString& sep);
+ QString makeColumnString (int column, const QString& sep, bool r_pasteable = true);
+ bool isColumnValid (int column);
bool is_valid;
// NOTE: The storage may contain more rows / columns than the current dimensions of the table. This is so that no data gets
// 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;
+ int last_valid_row; // to save validizing the entire table on each change, we keep track of validity per column
QStringList storage;
QString cached_tab_joined_string;
};
@@ -86,8 +85,7 @@
QTableView *display;
RKMatrixInputModel *model;
- // these two to avoid recursion:
- bool updating_dimensions;
+ // to avoid recursion:
bool updating_tsv_data;
};
Modified: trunk/rkward/rkward/plugins/testing/matrix1.xml
===================================================================
--- trunk/rkward/rkward/plugins/testing/matrix1.xml 2012-10-31 11:12:30 UTC (rev 4402)
+++ trunk/rkward/rkward/plugins/testing/matrix1.xml 2012-10-31 12:03:24 UTC (rev 4403)
@@ -18,7 +18,7 @@
</tab>
<tab label="User resizable vector">
<row>
- <matrix id="matrixb" mode="real" columns="1" allow_user_resize_columns="false" label="Enter data (0.0 .. 1.0)" min="0" max="1"/>
+ <matrix id="matrixb" mode="real" columns="1" allow_user_resize_columns="false" label="Enter data (0.0 .. 1.0)" fixed_width="true" min="0" max="1"/>
<stretch/>
</row>
</tab>
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