Browse Source

Improve excess row handling in new batch window

Neal Wilson 11 years ago
parent
commit
3c471ec307
2 changed files with 164 additions and 5 deletions
  1. 16
    1
      config/Windows/newbatch.xml
  2. 148
    4
      src/typica.w

+ 16
- 1
config/Windows/newbatch.xml View File

21
         </layout>
21
         </layout>
22
         <label>Green Coffee:</label>
22
         <label>Green Coffee:</label>
23
         <sqltablearray columns="2" id="greens">
23
         <sqltablearray columns="2" id="greens">
24
-            <column name="Coffee" delegate="sql" showdata="true" null="false" data="0" display="1">SELECT id, name FROM coffees WHERE quantity &lt;&gt; 0 ORDER BY name</column>
24
+            <column name="Coffee" delegate="sql" showdata="true" null="true" nulltext="Delete" nulldata="delete" data="0" display="1">SELECT id, name FROM coffees WHERE quantity &lt;&gt; 0 ORDER BY name</column>
25
             <column name="Weight" />
25
             <column name="Weight" />
26
         </sqltablearray>
26
         </sqltablearray>
27
         <layout type="horizontal">
27
         <layout type="horizontal">
119
 				}
119
 				}
120
 			}
120
 			}
121
 			model.dataChanged.connect(function() {
121
 			model.dataChanged.connect(function() {
122
+				var deleteRow = -1;
123
+				/* The combo box delegate updates user data before display data
124
+				   and this code is executed before the model update is fully
125
+				   complete. Rather than rely on this behavior continuing, we
126
+				   check that the display value has also been updated and defer
127
+				   row removal until both updates are complete.
128
+				*/
129
+				while((deleteRow = table.findData("delete", 0)) > -1) {
130
+					if(table.data(deleteRow, 0, 0) == "Delete") {
131
+						table.removeRow(table.findData("delete", 0));
132
+					} else {
133
+						break;
134
+					}
135
+				}
122
 				green.text = table.columnSum(1, 0);
136
 				green.text = table.columnSum(1, 0);
123
 				table.resizeColumnToContents(0);
137
 				table.resizeColumnToContents(0);
124
                 if(parseFloat(green.text) > 0)
138
                 if(parseFloat(green.text) > 0)
160
             var profilebutton = findChildObject(this, 'load');
174
             var profilebutton = findChildObject(this, 'load');
161
             profilebutton.setEnabled(false);
175
             profilebutton.setEnabled(false);
162
             roasted['currentIndexChanged(int)'].connect(function() {
176
             roasted['currentIndexChanged(int)'].connect(function() {
177
+				table.clear();
163
                 var query = new QSqlQuery();
178
                 var query = new QSqlQuery();
164
                 var q = "SELECT EXISTS(SELECT 1 FROM item_files WHERE item = ";
179
                 var q = "SELECT EXISTS(SELECT 1 FROM item_files WHERE item = ";
165
                 q = q + roasted.currentData();
180
                 q = q + roasted.currentData();

+ 148
- 4
src/typica.w View File

5114
 @<Assign column delegate from SQL@>=
5114
 @<Assign column delegate from SQL@>=
5115
 SqlComboBoxDelegate *delegate = new SqlComboBoxDelegate;
5115
 SqlComboBoxDelegate *delegate = new SqlComboBoxDelegate;
5116
 SqlComboBox *widget = new SqlComboBox();
5116
 SqlComboBox *widget = new SqlComboBox();
5117
+if(currentElement.hasAttribute("nulltext"))
5118
+{
5119
+	widget->setNullText(currentElement.attribute("nulltext"));
5120
+}
5121
+if(currentElement.hasAttribute("nulldata"))
5122
+{
5123
+	widget->setNullData(QVariant(currentElement.attribute("nulldata")));
5124
+}
5117
 if(currentElement.hasAttribute("null"))
5125
 if(currentElement.hasAttribute("null"))
5118
 {
5126
 {
5119
 	if(currentElement.attribute("null") == "true")
5127
 	if(currentElement.attribute("null") == "true")
5567
 QScriptValue SaltTable_quotedColumnArray(QScriptContext *context,
5575
 QScriptValue SaltTable_quotedColumnArray(QScriptContext *context,
5568
                                          QScriptEngine *engine);
5576
                                          QScriptEngine *engine);
5569
 QScriptValue SaltTable_setData(QScriptContext *context, QScriptEngine *engine);
5577
 QScriptValue SaltTable_setData(QScriptContext *context, QScriptEngine *engine);
5578
+QScriptValue SaltTable_clear(QScriptContext *context, QScriptEngine *engine);
5579
+QScriptValue SaltTable_removeRow(QScriptContext *context, QScriptEngine *engine);
5580
+QScriptValue SaltTable_findData(QScriptContext *context, QScriptEngine *engine);
5570
 
5581
 
5571
 @ There are times when it is useful to obtain the sum of values in a column of
5582
 @ There are times when it is useful to obtain the sum of values in a column of
5572
 a SaltTable object. For example, when a column represents the weight of the
5583
 a SaltTable object. For example, when a column represents the weight of the
5697
 	return retval;
5708
 	return retval;
5698
 }
5709
 }
5699
 
5710
 
5711
+@ There are times when it is useful to clear the content of a table. This is
5712
+used, for example, in the green coffees table after changing the roasted coffee
5713
+item to eliminate excess rows in the case where the previously selected item
5714
+was a pre-roast blend.
5715
+
5716
+@<Functions for scripting@>=
5717
+QScriptValue SaltTable_clear(QScriptContext *context, QScriptEngine *)
5718
+{
5719
+	QTableView *self = getself<QTableView *>(context);
5720
+	SaltModel *model = qobject_cast<SaltModel *>(self->model());
5721
+	model->clear();
5722
+	return QScriptValue();
5723
+}
5724
+
5725
+@ It is sometimes useful to remove a row from a table. This is done in the new
5726
+batch window when the coffee for a row is set to a NULL item.
5727
+
5728
+@<Functions for scripting@>=
5729
+QScriptValue SaltTable_removeRow(QScriptContext *context, QScriptEngine *engine)
5730
+{
5731
+	QTableView *self = getself<QTableView *>(context);
5732
+	SaltModel *model = qobject_cast<SaltModel *>(self->model());
5733
+	int row = argument<int>(0, context);
5734
+	return engine->newVariant(model->removeRow(row));
5735
+}
5736
+
5737
+@ To remove the correct row, it is sometimes useful to query the table for
5738
+special values. This is done with the |findData()| method on the underlying
5739
+model.
5740
+
5741
+@<Functions for scripting@>=
5742
+QScriptValue SaltTable_findData(QScriptContext *context, QScriptEngine *engine)
5743
+{
5744
+	QTableView *self = getself<QTableView *>(context);
5745
+	SaltModel *model = qobject_cast<SaltModel *>(self->model());
5746
+	QVariant value = argument<QVariant>(0, context);
5747
+	int column = argument<int>(1, context);
5748
+	return engine->newVariant(model->findData(value, column));
5749
+}
5750
+
5700
 @ These functions need to be added as properties of the table when it is passed
5751
 @ These functions need to be added as properties of the table when it is passed
5701
 to the host environment.
5752
 to the host environment.
5702
 
5753
 
5716
 	value.setProperty("data", engine->newFunction(SaltTable_data));
5767
 	value.setProperty("data", engine->newFunction(SaltTable_data));
5717
 	value.setProperty("model", engine->newFunction(SaltTable_model));
5768
 	value.setProperty("model", engine->newFunction(SaltTable_model));
5718
 	value.setProperty("setData", engine->newFunction(SaltTable_setData));
5769
 	value.setProperty("setData", engine->newFunction(SaltTable_setData));
5770
+	value.setProperty("clear", engine->newFunction(SaltTable_clear));
5771
+	value.setProperty("removeRow", engine->newFunction(SaltTable_removeRow));
5772
+	value.setProperty("findData", engine->newFunction(SaltTable_findData));
5719
 }
5773
 }
5720
 
5774
 
5721
 @ The |SqlComboBox| is another class that is not constructed from scripts but is
5775
 @ The |SqlComboBox| is another class that is not constructed from scripts but is
11896
 		QModelIndex parent(const QModelIndex &index) const;
11950
 		QModelIndex parent(const QModelIndex &index) const;
11897
 		QString arrayLiteral(int column, int role) const;
11951
 		QString arrayLiteral(int column, int role) const;
11898
 		QString quotedArrayLiteral(int column, int role) const;
11952
 		QString quotedArrayLiteral(int column, int role) const;
11953
+		void clear();
11954
+		bool removeRows(int row, int count,
11955
+		                const QModelIndex &parent = QModelIndex());
11956
+		int findData(const QVariant &value, int column, int role = Qt::UserRole);
11899
 };
11957
 };
11900
 
11958
 
11901
 @ The only unique methods in this class are the |arrayLiteral| and
11959
 @ The only unique methods in this class are the |arrayLiteral| and
12166
 	return QModelIndex();
12224
 	return QModelIndex();
12167
 }
12225
 }
12168
 
12226
 
12227
+@ There are some times when it is useful to clear the model data. Note that
12228
+column header data is retained and the table will contain a single empty row
12229
+after this method is called.
12230
+
12231
+@<SaltModel Implementation@>=
12232
+void SaltModel::clear()
12233
+{
12234
+	beginResetModel();
12235
+	modelData.clear();
12236
+	@<Expand the SaltModel@>@;
12237
+	endResetModel();
12238
+}
12239
+
12240
+@ Another commonly useful operation is the ability to remove rows from the
12241
+model. The new batch window uses this feature to eliminate rows in which the
12242
+coffee is set to NULL. Note that if all rows of the model are removed, a new
12243
+empty row will be created.
12244
+
12245
+@<SaltModel Implementation@>=
12246
+bool SaltModel::removeRows(int row, int count,
12247
+                           const QModelIndex &parent)
12248
+{
12249
+	if(parent == QModelIndex())
12250
+	{
12251
+		if(row >= 0 && count > 0 && (row + count - 1) < modelData.size())
12252
+		{
12253
+			beginRemoveRows(parent, row, row + count - 1);
12254
+			for(int i = 0; i < count; i++)
12255
+			{
12256
+				modelData.removeAt(row);
12257
+			}
12258
+			endRemoveRows();
12259
+			if(modelData.size() == 0)
12260
+			{
12261
+				beginInsertRows(parent, 0, 0);
12262
+				@<Expand the SaltModel@>@;
12263
+				endInsertRows();
12264
+			}
12265
+			return true;
12266
+		}
12267
+	}
12268
+	return false;
12269
+}
12270
+
12271
+@ To find the row number for removal operations it is useful to search for
12272
+special values on a given role. The |findData()| method returns the first row
12273
+in which the given value matches for a particular column and a particular role
12274
+or |-1| if no such match exists.
12275
+
12276
+@<SaltModel Implementation@>=
12277
+int SaltModel::findData(const QVariant &value, int column, int role)
12278
+{
12279
+	for(int i = 0; i < modelData.size(); i++)
12280
+	{
12281
+		if(modelData.at(i).size() > column)
12282
+		{
12283
+			if(modelData.at(i).at(column).contains(role))
12284
+			{
12285
+				if(modelData.at(i).at(column).value(role) == value)
12286
+				{
12287
+					return i;
12288
+				}
12289
+			}
12290
+		}
12291
+	}
12292
+	return -1;
12293
+}
12294
+
12169
 @* A Delegate for SQL Relations.
12295
 @* A Delegate for SQL Relations.
12170
 
12296
 
12171
 \noindent The first column of the table view being described is responsible for
12297
 \noindent The first column of the table view being described is responsible for
12191
 	int dataColumn;
12317
 	int dataColumn;
12192
 	int displayColumn;
12318
 	int displayColumn;
12193
 	bool dataColumnShown;
12319
 	bool dataColumnShown;
12320
+	QString specialNullText;
12321
+	QVariant specialNullData;
12194
 	public:@/
12322
 	public:@/
12195
 		SqlComboBox();
12323
 		SqlComboBox();
12196
 		~SqlComboBox();
12324
 		~SqlComboBox();
12200
 		void addSqlOptions(QString query);
12328
 		void addSqlOptions(QString query);
12201
 		void setDataColumn(int column);
12329
 		void setDataColumn(int column);
12202
 		void setDisplayColumn(int column);
12330
 		void setDisplayColumn(int column);
12203
-		void showData(bool show);@t\2@>@/
12331
+		void showData(bool show);
12332
+		void setNullText(QString nullText);
12333
+		void setNullData(QVariant nullData);@t\2@>@/
12204
 }@t\kern-3pt@>;
12334
 }@t\kern-3pt@>;
12205
 
12335
 
12206
 @ In order to make this class work a little more nicely as an item delegate,
12336
 @ In order to make this class work a little more nicely as an item delegate,
12233
 @ Next, there is a need to know if the NULL value may legally be selected. Where
12363
 @ Next, there is a need to know if the NULL value may legally be selected. Where
12234
 this is the case, we generally want this to be inserted first. As the
12364
 this is the case, we generally want this to be inserted first. As the
12235
 |QComboBox| supports storing both display and user data, much of the code is a
12365
 |QComboBox| supports storing both display and user data, much of the code is a
12236
-thin wrapper around calls to the base class.
12366
+thin wrapper around calls to the base class. The text and data for the NULL
12367
+value can be set arbitrarily, which can be useful in certain cases. Note that
12368
+any customization of the NULL text or data must be set before a call to
12369
+|addNullOption()|.
12237
 
12370
 
12238
 @<SqlComboBox Implementation@>=
12371
 @<SqlComboBox Implementation@>=
12239
 void SqlComboBox::addNullOption()
12372
 void SqlComboBox::addNullOption()
12240
 {
12373
 {
12241
-	addItem(tr("Unknown"), QVariant(QVariant::String));
12374
+	addItem(specialNullText, specialNullData);
12375
+}
12376
+
12377
+void SqlComboBox::setNullText(QString nullText)
12378
+{
12379
+	specialNullText = nullText;
12380
+}
12381
+
12382
+void SqlComboBox::setNullData(QVariant nullData)
12383
+{
12384
+	specialNullData = nullData;
12242
 }
12385
 }
12243
 
12386
 
12244
 @ Typically, the SQL query used to populate this widget will request two columns
12387
 @ Typically, the SQL query used to populate this widget will request two columns
12300
 
12443
 
12301
 @<SqlComboBox Implementation@>=
12444
 @<SqlComboBox Implementation@>=
12302
 SqlComboBox::SqlComboBox() :
12445
 SqlComboBox::SqlComboBox() :
12303
-	dataColumn(0), displayColumn(0), dataColumnShown(false)
12446
+	dataColumn(0), displayColumn(0), dataColumnShown(false),
12447
+	specialNullText(tr("Unknown")), specialNullData(QVariant::String)
12304
 {
12448
 {
12305
 	view()->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
12449
 	view()->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
12306
 }
12450
 }

Loading…
Cancel
Save