wxFileDialog SetDirectory and SetFilename Seem to be ignored Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
jamescobban
Knows some wx things
Knows some wx things
Posts: 30
Joined: Sun Feb 01, 2009 12:38 am

wxFileDialog SetDirectory and SetFilename Seem to be ignored

Post by jamescobban » Sun Jun 14, 2009 9:52 pm

I call the following two methods to set the default directory and filename

Code: Select all

SetDirectory("/media/disk-1/Documents and Settings/Jim Cobban/My Documents/FamilyTree");
SetFilename("Cobban.GED");
and then without calling any other methods on the dialog I call GetDirectory and GetFilename, with the following results:

Code: Select all

GetDirectory()="" 
GetFilename()=""
and when I call ShowModal it displays the contents of the directory that I invoked the program from, which I presume is the (undocumented) default.

What am I not understanding?

jamescobban
Knows some wx things
Knows some wx things
Posts: 30
Joined: Sun Feb 01, 2009 12:38 am

Post by jamescobban » Mon Jun 15, 2009 1:38 am

I am really very puzzled by this. I have looked at the header code and see that all that SetDirectory etc. do is change the members, so there is absolutely no way that this can be happening, and yet it is.

The only thing a bit unusual that I am doing is packaging all of the unique functionality that I am adding as a class derived from wxFileDialog:

Code: Select all

class OpenFileDialog : public wxFileDialog
{
public:


	OpenFileDialog( GenTool *		tool,
		wxFrame *		parent);

	virtual ~OpenFileDialog();

};
I get the parameters to configure the dialog from an XML file loaded by the GenTool class:

Code: Select all

OpenFileDialog::OpenFileDialog( GenTool *	tool,
								wxFrame *	parent)
	: wxFileDialog(	parent,
					"Choose a file",
					wxT(std::getenv("HOME")),		// directory
					"",		// initial file name
					"GEDCOM files (*.ged)|*.ged;*.GED",
					wxFD_FILE_MUST_EXIST + wxFD_CHANGE_DIR)
{
	std::cerr << "OpenFileDialog::OpenFileDialog(tool=" << tool <<
						", parent=" << parent << ")\n";
	std::cerr << "start: GetDirectory()=\"" << GetDirectory()
		<< "\", GetFilename()=\"" << GetFilename() << "\"\n";

	// get configuration for dialog
	wxXmlNode * openCfg	= tool->getConfig("open");
	wxXmlNode *	child	= openCfg->GetChildren();
	while (child)
	{
		if (child->GetType() == wxXML_TEXT_NODE)
		{
			std::cerr << "SetMessage(\"" << child->GetContent().Trim(true) << "\")\n";
	    	SetMessage(child->GetContent().Trim(true));
		}
		if (child->GetName().Cmp("last") == 0)
		{
			std::cerr << "last: ";
			wxString	lastFn	= child->GetPropVal(wxT("fn"),
													wxT(""));
			std::cerr << "lastFn=\"" << lastFn << "\"\n";
			size_t		endDir	= lastFn.find_last_of('/', lastFn.length() - 1);
			std::cerr << "endDir=" << endDir << ", length=" << lastFn.length() << "\n";
			if (endDir == std::string::npos)
			{			// no directory separator
				std::cerr << "SetFilename(\"" << lastFn << "\")\n";
				SetFilename(lastFn);
			}
			else
			{
				std::cerr << "SetDirectory(\"" << lastFn.substr(0, endDir) << "\")\n";
				SetDirectory(lastFn.substr(0, endDir));
				std::cerr << "SetFilename(\"" << lastFn.substr(endDir + 1) << "\")\n";
				SetFilename(lastFn.substr(endDir + 1));
			}
		}
		else
		{
			std::cerr << "unexpected tag <" << child->GetName() << ">\n";
		}
		child	= child->GetNext();
	}		// loop through children
	std::cerr << "return: GetDirectory()=\"" << GetDirectory()
		<< "\", GetFilename()=\"" << GetFilename() << "\"\n";
}		//  OpenFileDialog::OpenFileDialog
Note that even though in the constructor I have explicitly initialized Path to the user's HOME directory, the printout issued right at the top already indicates that GetDirectory returns an empty string!

protocol
Moderator
Moderator
Posts: 680
Joined: Wed Jan 18, 2006 6:13 pm
Location: Dallas, TX
Contact:

Post by protocol » Mon Jun 15, 2009 2:42 am

Code: Select all

wxFD_FILE_MUST_EXIST + wxFD_CHANGE_DIR) 
I'm not sure I have ever seen the "+" operator used for flags, usually "|" operator is used.

Works fine for me, you may want to check the return value set by your getenv call.

Code: Select all

wxT(std::getenv("HOME")), 
// try this
wxString(std::getenv("HOME")), 
Even more so, try passing the return to wxString instead of wxT macro. or use http://docs.wxwidgets.org/stable/wx_env ... l#wxgetenv

Also, keep in mind wxLogDebug is a better choice than std::err.

You seem to be attached to std namespace, keep in mind you are using a mature framework. You should look to it more often for the common tasks and cross-platform compatibility.

regards.
/* UIKit && wxWidgets 2.8 && Cocoa && .Net */
QuRegExmm
wxPCRE & ObjPCRE - Regex It!

jamescobban
Knows some wx things
Knows some wx things
Posts: 30
Joined: Sun Feb 01, 2009 12:38 am

Post by jamescobban » Mon Jun 15, 2009 4:35 pm

protocol wrote:
Works fine for me, you may want to check the return value set by your getenv call.

Even more so, try passing the return to wxString instead of wxT macro. or use http://docs.wxwidgets.org/stable/wx_env ... l#wxgetenv

You seem to be attached to std namespace, keep in mind you are using a mature framework. You should look to it more often for the common tasks and cross-platform compatibility.
Thank you for trying to help me.

One of my concerns is that wxWidgets does not itself use a name space, which is to my mind a sign of immaturity. C++ namespaces have been around for more than 10 years now.

I tried using wxGetEnv, but I could not get it to work. When I try:

Code: Select all

wxGetEnv(wxT("HOME"))
for example, I get an error: too few arguments to function ‘bool wxGetEnv(const wxString&, wxString*)’

This is presumably because the single parameter wxGetEnv documented in the site you pointed me at is documented as a macro, not a function, even though it's name does not follow the standard convention of clearly identifying macros by the use of all upper-case letters. This is a bad programming habit picked up from the original C library. In C++ macros are further deprecated because they interfere with the ability of the compiler to implement polymorphism, unlike inline methods. Furthermore the wxWidgets documentation itself warns that this form of wxGetEnv is not portable.

The only code that I can get to compile is:

Code: Select all

	: wxFileDialog(	parent,
					"Choose a file",
					wxString(std::getenv("HOME")),		// directory
					"",		// initial file name
					"GEDCOM files (*.ged)|*.ged;*.GED",
					wxFD_FILE_MUST_EXIST | wxFD_CHANGE_DIR)
And this still gives the same output. The diagnostic output from calling this constructor remains:

Code: Select all

OpenFileDialog::OpenFileDialog(tool=0x99f98e8, parent=0x9a50cd0)
std::getenv("HOME")="/home/jcobban"
start: GetDirectory()="", GetFilename()=""
start: GetWildcard()="GEDCOM files (*.ged)|*.ged;*.GED
GenTool::getConfig(const char * "open")
GenTool::getConfig(wxString "open")
last: lastFn="/media/disk-1/Documents and Settings/Jim Cobban/My Documents/FamilyTree/Cobban.GED"
endDir=71, length=82
SetDirectory("/media/disk-1/Documents and Settings/Jim Cobban/My Documents/FamilyTree")
SetFilename("Cobban.GED")
last: GetDirectory()="", GetFilename()=""
return: GetDirectory()="", GetFilename()=""
As you can see, from the output of GetWildcard, if I pass a const char * literal as a parameter to either the wxFileDialog constructor or the SetXxx methods it takes, but if I pass anything else it is treated as if I passed a zero-length string. This is particular puzzling with the SetXxx methods where I am passing the output of the wxString::substr method, which is supposed to be returning a wxString, surely an ideal parameter to a const wxString & formal parameter.

Even when I modify the code to explicitly put the parameters into instances of wxString first, whose values I print out just before calling the SetXxxx methods, I still do not get the right values:

Code: Select all

				wxString	directory, filename;
				directory	= lastFn.substr(0, endDir);
				filename	= lastFn.substr(endDir + 1);
				std::cerr << "SetDirectory("" << directory << "")\n";
				SetDirectory(directory);
				std::cerr << "SetFilename("" << filename << "")\n";
				SetFilename(filename);
				std::cerr << "last: GetDirectory()="" << GetDirectory()
					<< "", GetFilename()="" << GetFilename() << ""\n";

Paulsen
Experienced Solver
Experienced Solver
Posts: 53
Joined: Wed May 24, 2006 1:56 pm
Location: Germany

Post by Paulsen » Mon Jun 15, 2009 5:04 pm

Maybe a dumb question: What platform and build environment are you on? "Documents and Settings" has a definite Windows-tone. Are you sure you are specifying the directory in a way your OS will understand?
Paulsen

TrV
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 630
Joined: Wed Jul 04, 2007 1:12 pm

Post by TrV » Mon Jun 15, 2009 5:23 pm

protocol wrote:

Code: Select all

wxFD_FILE_MUST_EXIST + wxFD_CHANGE_DIR) 
I'm not sure I have ever seen the "+" operator used for flags, usually "|" operator is used.
'+' for number which are powers of 2 (1, 2, 4, 8 ) is equivalent to '|', logical OR.

jamescobban
Knows some wx things
Knows some wx things
Posts: 30
Joined: Sun Feb 01, 2009 12:38 am

Post by jamescobban » Mon Jun 15, 2009 10:45 pm

Paulsen wrote:Maybe a dumb question: What platform and build environment are you on? "Documents and Settings" has a definite Windows-tone. Are you sure you are specifying the directory in a way your OS will understand?
Sorry, I should have made that clear, as looking through the wxWidgets code I see that there are a lot of specializations and therefore the problem I am having may be specific to a particular implementation.

I am running wxWidgets 2.8.10 with gcc version 4.3.3 on Ubuntu 9.04 with Gtk 2.4. I have a Windows NTFS file system mounted on Ubuntu (which you can see because the file path starts with "/media/disk-1" instead of "C:") because the data that my application works with is created by a Windows app. I will eventually be doing a cross-compile to create a Windows version of my app, which is the whole point of using wxWidgets rather than coding directly to Gtk, but it is a lot easier developing and testing on Linux.

By the way; noting that the GetXxxx functions are virtual, as they should be, I considered the possibility that the vtable for my class was pointing at the wrong implementation, so I have also tried explicitly qualifying the methods with wxFileDialog::, which should guarantee that I am invoking the Gtk specific version of the method. There is no change in behavior.

Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria » Tue Jun 16, 2009 12:06 am

Do the same methods work fine if you don't try to have them read files from another filesystem?
"Keyboard not detected. Press F1 to continue"
-- Windows

jamescobban
Knows some wx things
Knows some wx things
Posts: 30
Joined: Sun Feb 01, 2009 12:38 am

Post by jamescobban » Tue Jun 16, 2009 2:39 am

Auria wrote:Do the same methods work fine if you don't try to have them read files from another filesystem?
I don't understand your question. The methods don't read anything, they just set internal state variables of the dialog. In any event there is no way for the dialog to be able to tell whether the directory in question is on another file system, it is just a string of directory names.

The bottom line is that the methods work if they are called with a const char * literal, but not if they are called with a wxString variable. My app worked fine until I changed it to initialize the dialog from an XML initialization file, instead of hard-coding the directory and file name.

protocol
Moderator
Moderator
Posts: 680
Joined: Wed Jan 18, 2006 6:13 pm
Location: Dallas, TX
Contact:

Post by protocol » Tue Jun 16, 2009 3:01 am

jamescobban wrote: One of my concerns is that wxWidgets does not itself use a name space, which is to my mind a sign of immaturity. C++ namespaces have been around for more than 10 years now.
Namespaces are used to denote scope, to provide logical organization. All wxWidget entities are prefixed with "wx". By that virtue, there is really no need for namespaces within wxWidgets. In respects to maturity, that could be called defensive programming; protecting developer classes from name clashes with wxWidget classes.
TrV wrote:
protocol wrote:

Code: Select all

wxFD_FILE_MUST_EXIST + wxFD_CHANGE_DIR) 
I'm not sure I have ever seen the "+" operator used for flags, usually "|" operator is used.
'+' for number which are powers of 2 (1, 2, 4, 8 ) is equivalent to '|', logical OR.
Well, let me rephrase it, common convention is to use "|" for flags.
/* UIKit && wxWidgets 2.8 && Cocoa && .Net */
QuRegExmm
wxPCRE & ObjPCRE - Regex It!

Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria » Tue Jun 16, 2009 2:14 pm

jamescobban wrote:
Auria wrote:Do the same methods work fine if you don't try to have them read files from another filesystem?
I don't understand your question. The methods don't read anything, they just set internal state variables of the dialog. In any event there is no way for the dialog to be able to tell whether the directory in question is on another file system, it is just a string of directory names.
Having not coded wxFileDialog, I don't know what it does :)
jamescobban wrote: The bottom line is that the methods work if they are called with a const char * literal, but not if they are called with a wxString variable. My app worked fine until I changed it to initialize the dialog from an XML initialization file, instead of hard-coding the directory and file name.
The fact that could could pass char* might hint that you are using an ANSI build of wx. Is it the case? if so, I would strongly recommend using a unicode build. Your issue, in this case, might be one of encoding conversion (though i'm not sure how they could happen, but who knows)
One of my concerns is that wxWidgets does not itself use a name space, which is to my mind a sign of immaturity. C++ namespaces have been around for more than 10 years now.
That can also be a sign of very mature; wxWidgets was started before namespaces existed (or where implemented in common compilers) and changing this at this point would break all existing code for little benifit (though I would approve such a move even then.)
"Keyboard not detected. Press F1 to continue"
-- Windows

jamescobban
Knows some wx things
Knows some wx things
Posts: 30
Joined: Sun Feb 01, 2009 12:38 am

Post by jamescobban » Tue Jun 16, 2009 5:19 pm

The fact that could could pass char* might hint that you are using an ANSI build of wx. Is it the case? if so, I would strongly recommend using a unicode build. Your issue, in this case, might be one of encoding conversion (though i'm not sure how they could happen, but who knows)
I just did the build according to the instructions in install-gtk.txt. That is I issued "../configure --with-gtk". I did not explicitly request either an ANSI or a unicode build. How would I tell which the configure command chose to do?

Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria » Tue Jun 16, 2009 9:11 pm

To get a unicode build, pass option --enable-unicode (or whatever it's called, see ../configure --help)

It's indeed a shame the readme doesn't mention that; --with-gtk should not be needed, and --enable-unicode is highly recommended. wxWidgets 3.0 will feature major refactor of this (unicode will always be enabled), this may be why it was left this way in 2.8
"Keyboard not detected. Press F1 to continue"
-- Windows

jamescobban
Knows some wx things
Knows some wx things
Posts: 30
Joined: Sun Feb 01, 2009 12:38 am

Post by jamescobban » Wed Jun 17, 2009 5:14 pm

Auria wrote:To get a unicode build, pass option --enable-unicode (or whatever it's called, see ../configure --help)

It's indeed a shame the readme doesn't mention that; --with-gtk should not be needed, and --enable-unicode is highly recommended. wxWidgets 3.0 will feature major refactor of this (unicode will always be enabled), this may be why it was left this way in 2.8
I rebuilt wxWidgets with Unicode and made the required changes in my code to compile. The problem persists, except that it is now harder to debug because the unicode version of wxString does not behave well with std::cerr, displaying an address (presumably of its buffer) instead of the contents of the string.

jamescobban
Knows some wx things
Knows some wx things
Posts: 30
Joined: Sun Feb 01, 2009 12:38 am

Post by jamescobban » Wed Jun 17, 2009 5:23 pm

jamescobban wrote: I rebuilt wxWidgets with Unicode and made the required changes in my code to compile. The problem persists, except that it is now harder to debug because the unicode version of wxString does not behave well with std::cerr, displaying an address (presumably of its buffer) instead of the contents of the string.
The diagnostic output from my program is now:
OpenFileDialog::OpenFileDialog(tool=0x92613f8, parent=0x92baa50)
std::getenv("HOME")="/home/jcobban"
start: GetDirectory()="", GetFilename()=""
start: GetWildcard()="GEDCOM files (*.ged)|*.ged;*.GED
last: lastFn="/media/disk-1/Documents and Settings/Jim Cobban/My Documents/FamilyTree/Cobban.GED"
endDir=71, length=82
SetDirectory("/media/disk-1/Documents and Settings/Jim Cobban/My Documents/FamilyTree")
SetFilename("Cobban.GED")
last: GetDirectory()="", GetFilename()=""
return: GetDirectory()="", GetFilename()=""
As you can see, from the output of GetWildCard, it is possible for me to correctly initialize a state variable of wxFileDialog given a literal string (L"GEDCOM files (*.ged)|*.ged;*.GED" in the constructor in this case), but I still cannot initialize them from a wxString variable!

Should I report this as a bug?

Post Reply