Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site
Search in forums












SourceForge.net Logo
Home » U++ Library support » ArrayCtrl, HeaderCtrl & GridCtrl » AcceptRow broken when SetCtrl is used
AcceptRow broken when SetCtrl is used [message #16744] Wed, 09 July 2008 15:41 Go to next message
mrjt is currently offline  mrjt
Messages: 705
Registered: March 2007
Location: London
Contributor
ArrayCtrl::AcceptRow doesn't check any child ctrls set with SetCtrl() when accepting rows, which in turn can lead to dialogs being accepted with invalid data (a big problem!). A quick test case:
#include <CtrlLib/CtrlLib.h>
using namespace Upp;

GUI_APP_MAIN
{
	TopWindow wnd;
	ArrayCtrl ctrl;
	Button ok;
	Button cancel;
	Array<EditInt> edit;
	
	Rect r = Rect(0, 0, 200, 300);
	wnd.Sizeable().SetMinSize(r.GetSize());
	wnd.SetRect(r + GetScreenSize() / 2 - r.GetSize()/2);
	wnd.Add(ctrl.HSizePos().VSizePos(0, 28));
	wnd.Add(ok.SetLabel("OK").RightPos(88, 80).BottomPos(4, 22));
	wnd.Add(cancel.SetLabel("Cancel").RightPos(4, 80).BottomPos(4, 22));  
	wnd.Acceptor(ok, IDOK);
	wnd.Rejector(cancel, IDCANCEL);
	
	edit.SetCount(20);
	ctrl.AddColumn("EditInts (0-1)");
	ctrl.SetCount(20);	
	for (int i = 0; i < edit.GetCount(); i++) {
		edit[i].Min(0).Max(1) <<= 1;
		ctrl.SetCtrl(i, 0, edit[i]);	
	}

	wnd.Execute();
}

Just type 2 into one of the rows and then change row, this should trigger an Exclamation but doesn't. You will be also able to 'OK' the form with the invalid data still in the ctrl.

I've attempted to fix this myself but just adding a check in AcceptRow causes a stack overflow due to focus changes when an Exclamation is shown by the child's Accept() function, so I'll leave it to someone with better knowledge of ArrayCtrl.

I'd settle for just checking all the ctrls in the ArrayCtrl's Accept function if fixing AcceptRow is impossible/very difficult.

Cheers.

[Updated on: Wed, 09 July 2008 16:21]

Report message to a moderator

Re: AcceptRow broken when SetCtrl is used [message #16789 is a reply to message #16744] Fri, 11 July 2008 12:36 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
mrjt wrote on Wed, 09 July 2008 09:41

ArrayCtrl::AcceptRow doesn't check any child ctrls set with SetCtrl() when accepting rows, which in turn can lead to dialogs being accepted with invalid data (a big problem!). A quick test case:
#include <CtrlLib/CtrlLib.h>
using namespace Upp;

GUI_APP_MAIN
{
	TopWindow wnd;
	ArrayCtrl ctrl;
	Button ok;
	Button cancel;
	Array<EditInt> edit;
	
	Rect r = Rect(0, 0, 200, 300);
	wnd.Sizeable().SetMinSize(r.GetSize());
	wnd.SetRect(r + GetScreenSize() / 2 - r.GetSize()/2);
	wnd.Add(ctrl.HSizePos().VSizePos(0, 28));
	wnd.Add(ok.SetLabel("OK").RightPos(88, 80).BottomPos(4, 22));
	wnd.Add(cancel.SetLabel("Cancel").RightPos(4, 80).BottomPos(4, 22));  
	wnd.Acceptor(ok, IDOK);
	wnd.Rejector(cancel, IDCANCEL);
	
	edit.SetCount(20);
	ctrl.AddColumn("EditInts (0-1)");
	ctrl.SetCount(20);	
	for (int i = 0; i < edit.GetCount(); i++) {
		edit[i].Min(0).Max(1) <<= 1;
		ctrl.SetCtrl(i, 0, edit[i]);	
	}

	wnd.Execute();
}

Just type 2 into one of the rows and then change row, this should trigger an Exclamation but doesn't. You will be also able to 'OK' the form with the invalid data still in the ctrl.

I've attempted to fix this myself but just adding a check in AcceptRow causes a stack overflow due to focus changes when an Exclamation is shown by the child's Accept() function, so I'll leave it to someone with better knowledge of ArrayCtrl.

I'd settle for just checking all the ctrls in the ArrayCtrl's Accept function if fixing AcceptRow is impossible/very difficult.

Cheers.


This seems to fix the problem:

bool ArrayCtrl::AcceptRow() {
	ASSERT(IsCursor());
	int i;
	for(i = 0; i < column.GetCount(); i++) {
		Column& m = column[i];
		if(m.edit && !m.edit->Accept())
			return false;
		if(IsCtrl(cursor, i)) {
			Ctrl *c =  GetCtrl(cursor, i).ctrl;
			acceptingrow++;
			bool b = c->Accept();
			acceptingrow--;
			if(!b)
				return false;
		}
	}
	for(i = 0; i < control.GetCount(); i++)
		if(!control[i].ctrl->Accept())
			return false;
	acceptingrow++;
	bool ar = WhenAcceptRow() && UpdateRow();
	acceptingrow--;
	if(!ar) {
		SetCursorEditFocus();
		return false;
	}
	bool b = editmode;
	EndEdit();
	SetCtrls();
	ClearModify();
	if(b)
		WhenAcceptEdit();
	return true;
}



Not that I would like such fragile code Smile

Mirek
Re: AcceptRow broken when SetCtrl is used [message #19896 is a reply to message #16789] Fri, 30 January 2009 13:14 Go to previous messageGo to next message
mrjt is currently offline  mrjt
Messages: 705
Registered: March 2007
Location: London
Contributor
luzr wrote on Fri, 11 July 2008 11:36

mrjt wrote on Wed, 09 July 2008 09:41

ArrayCtrl::AcceptRow doesn't check any child ctrls set with SetCtrl() when accepting rows, which in turn can lead to dialogs being accepted with invalid data (a big problem!). A quick test case:
#include <CtrlLib/CtrlLib.h>
using namespace Upp;

GUI_APP_MAIN
{
	TopWindow wnd;
	ArrayCtrl ctrl;
	Button ok;
	Button cancel;
	Array<EditInt> edit;
	
	Rect r = Rect(0, 0, 200, 300);
	wnd.Sizeable().SetMinSize(r.GetSize());
	wnd.SetRect(r + GetScreenSize() / 2 - r.GetSize()/2);
	wnd.Add(ctrl.HSizePos().VSizePos(0, 28));
	wnd.Add(ok.SetLabel("OK").RightPos(88, 80).BottomPos(4, 22));
	wnd.Add(cancel.SetLabel("Cancel").RightPos(4, 80).BottomPos(4, 22));  
	wnd.Acceptor(ok, IDOK);
	wnd.Rejector(cancel, IDCANCEL);
	
	edit.SetCount(20);
	ctrl.AddColumn("EditInts (0-1)");
	ctrl.SetCount(20);	
	for (int i = 0; i < edit.GetCount(); i++) {
		edit[i].Min(0).Max(1) <<= 1;
		ctrl.SetCtrl(i, 0, edit[i]);	
	}

	wnd.Execute();
}

Just type 2 into one of the rows and then change row, this should trigger an Exclamation but doesn't. You will be also able to 'OK' the form with the invalid data still in the ctrl.

I've attempted to fix this myself but just adding a check in AcceptRow causes a stack overflow due to focus changes when an Exclamation is shown by the child's Accept() function, so I'll leave it to someone with better knowledge of ArrayCtrl.

I'd settle for just checking all the ctrls in the ArrayCtrl's Accept function if fixing AcceptRow is impossible/very difficult.

Cheers.


This seems to fix the problem:

bool ArrayCtrl::AcceptRow() {
	ASSERT(IsCursor());
	int i;
	for(i = 0; i < column.GetCount(); i++) {
		Column& m = column[i];
		if(m.edit && !m.edit->Accept())
			return false;
		if(IsCtrl(cursor, i)) {
			Ctrl *c =  GetCtrl(cursor, i).ctrl;
			acceptingrow++;
			bool b = c->Accept();
			acceptingrow--;
			if(!b)
				return false;
		}
	}
	for(i = 0; i < control.GetCount(); i++)
		if(!control[i].ctrl->Accept())
			return false;
	acceptingrow++;
	bool ar = WhenAcceptRow() && UpdateRow();
	acceptingrow--;
	if(!ar) {
		SetCursorEditFocus();
		return false;
	}
	bool b = editmode;
	EndEdit();
	SetCtrls();
	ClearModify();
	if(b)
		WhenAcceptEdit();
	return true;
}



Not that I would like such fragile code Smile

Mirek

This is either broken again or was never fixed, the code in the repo doesn't match the code above.
Re: AcceptRow broken when SetCtrl is used [message #19993 is a reply to message #19896] Sun, 08 February 2009 10:40 Go to previous message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Not sure what went wrong. It is back again.

If you have some time to check if it is fixed now, would be great...

Mirek
Previous Topic: Problem with GridCtrl: dragging rows
Next Topic: Add Ctrls to ArrayCtrl
Goto Forum:
  


Current Time: Sun Apr 28 22:28:43 CEST 2024

Total time taken to generate the page: 0.02563 seconds