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.
Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria » Wed Jun 17, 2009 5:27 pm

I would say, try to reproduce this in a minimal compilable sample.

Then we can try it; then we can gather information about it. If it turns out no one else has a solution, then you can post this small example to a bug report and get the most attention.

PS: you can print wxString to std::cout/std::cerr with a small call to .mb_str()
"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 7:10 pm

Auria wrote:I would say, try to reproduce this in a minimal compilable sample.
OK I have trimmed this down to a single source file and single header file with no external inputs. This generates the following output which indicates that the values of the wxString parameters are ignored while the const wchar * parameters are honored.

Code: Select all

std::getenv("HOME")="/home/jcobban"
start: GetDirectory()="", GetFilename()="0xb7701a58"
start: GetWildcard()="GEDCOM files (*.ged)|*.ged;*.GED
SetDirectory("/home/jcobban")
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()=""
The header for this program is:

Code: Select all

#ifndef OPEN_FILE_DIALOG_H_
#define OPEN_FILE_DIALOG_H_

#include <wx/wx.h>

class OpenFileDialog : public wxFileDialog
{
public:

	OpenFileDialog( wxFrame *		parent);

	virtual ~OpenFileDialog();
	void onQuit(wxCommandEvent& event);

};		// class OpenFileDialog

class GenFrame : public wxFrame
{
public:

	GenFrame();

	virtual ~GenFrame();

	static int main();

};		// GenFrame
class GenTool : public wxApp
{
public:

    virtual bool OnInit();
};

#endif /*OPEN_FILE_DIALOG_H_*/
And the source file contains:

Code: Select all

#include <cstdlib>
#include <cstring>
#include <iostream>
#include "OpenFileDialog.h"

OpenFileDialog::OpenFileDialog( wxFrame *	parent)
	: wxFileDialog(	parent,
					L"Choose a file",
					::wxGetHomeDir(),		// home directory
					L"",				// initial file name
					L"GEDCOM files (*.ged)|*.ged;*.GED",
					wxFD_FILE_MUST_EXIST | wxFD_CHANGE_DIR)
{
	wxString	dftDir = ::wxGetHomeDir();
	std::wcerr << "std::getenv("HOME")="" << dftDir.c_str() << ""\n";

	std::wcerr << "start: GetDirectory()="" << GetDirectory().c_str()
		<< "", GetFilename()="" << GetFilename() << ""\n";
	std::wcerr << "start: GetWildcard()="" << GetWildcard().c_str() << "\n";
	std::wcerr << "SetDirectory("" << dftDir.c_str() << "")\n";
	SetDirectory(dftDir);

	// get configuration for dialog
			wxString	lastFn	= L"/media/disk-1/Documents and Settings/Jim Cobban/My Documents/FamilyTree/Cobban.GED";
			std::wcerr << "lastFn="" << lastFn.c_str() << ""\n";
			size_t		endDir	= lastFn.find_last_of('/', lastFn.length() - 1);
			std::wcerr << "endDir=" << endDir << ", length=" << lastFn.length() << "\n";
			if (endDir == std::string::npos)
			{			// no directory separator
				std::wcerr << "SetFilename("" << lastFn.c_str() << "")\n";
				SetFilename(lastFn);
			}			// no directory separator
			else
			{			// directory separator present
				wxString	directory, filename;
				directory	= lastFn.substr(0, endDir);
				filename	= lastFn.substr(endDir + 1);
				std::wcerr << "SetDirectory("" << directory.c_str() << "")\n";
				SetDirectory(directory);
				std::wcerr << "SetFilename("" << filename.c_str() << "")\n";
				SetFilename(filename);
				std::wcerr << "last: GetDirectory()="" << GetDirectory().c_str()
					<< "", GetFilename()="" << GetFilename().c_str() << ""\n";
			}			// directory separator present
	std::wcerr << "return: GetDirectory()="" << GetDirectory().c_str()
		<< "", GetFilename()="" << GetFilename().c_str() << ""\n";
}		//  OpenFileDialog::OpenFileDialog

//****************************************
//
//  OpenFileDialog::~OpenFileDialog
//
//  Destructor.  Release child resources.
//
//****************************************
OpenFileDialog::~OpenFileDialog()
{

}			//  OpenFileDialog::~OpenFileDialog

GenFrame::GenFrame( )
: wxFrame( (wxFrame*) NULL,
	    -1,
	    L"Test Driver",
	    wxPoint(50, 50),
	    wxSize(500, 500) )
{
	// allocate and initialize the open file dialog
	OpenFileDialog * openFileDialog = new OpenFileDialog(this);
	if (openFileDialog->ShowModal() == wxID_OK){
	    wxString fileName = openFileDialog->GetPath();
	}

}	//  GenFrame::GenFrame

GenFrame::~GenFrame()
{
}	//  GenFrame::~GenFrame

IMPLEMENT_APP(GenTool)

//****************************************
//
//  GenTool::OnInit
//
//  Method called when GUI initialization complete.
//
//****************************************
bool GenTool::OnInit()
{
	// create an instance of the main window
	GenFrame *frame = new GenFrame();

	// display the window as the top window for this application
	std::cerr << "frame->Show(TRUE);\n";
	frame->Show(TRUE);
	SetTopWindow(frame);

	// continue in the event loop
	return TRUE;
}

User avatar
doublemax
Moderator
Moderator
Posts: 15490
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax » Wed Jun 17, 2009 8:33 pm

GetFilename() and SetFilename() are simple getters and setters, i just can't think of anything going wrong there.

I noticed that the "correct" output is given when you print a string directly, but not when you use the return value from a method.

I suspect it's just a display problem with std::

Could you test this code please:

Code: Select all

wxString dftDir = ::wxGetHomeDir();
std::wcerr << "dftDir="" << dftDir.c_str() << ""\n";
std::wcerr << "wxGetHomeDir()="" << ::wxGetHomeDir().c_str() << ""\n";

// and now we try wxLogMessage for the same
wxLogMessage(wxT("dftDir='%s'"), dftDir.c_str());
wxLogMessage(wxT("wxGetHomeDir()='%s'"), ::wxGetHomeDir().c_str());
BTW: When you use the wxT() macro around string literals, your code will work on Unicode and ANSI and you don't have to put the "L" in front (that's all that macro actually does)
Use the source, Luke!

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

Post by Auria » Thu Jun 18, 2009 12:32 am

Hmm not sure what's up with your quotes ("), they're all messed up

Anyhow, I ran the following code :

Code: Select all

#ifndef OPEN_FILE_DIALOG_H_
#define OPEN_FILE_DIALOG_H_

#include <wx/wx.h>

class OpenFileDialog : public wxFileDialog
    {
    public:
        
        OpenFileDialog( wxFrame *              parent);
        
        virtual ~OpenFileDialog();
        void onQuit(wxCommandEvent& event);
        
    };            // class OpenFileDialog

class GenFrame : public wxFrame
    {
    public:
        
        GenFrame();
        
        virtual ~GenFrame();
        
        static int main();
        
    };            // GenFrame
class GenTool : public wxApp
    {
    public:
        
        virtual bool OnInit();
    };

#endif /*OPEN_FILE_DIALOG_H_*/


#include <cstdlib>
#include <cstring>
#include <iostream>
//
//#include "OpenFileDialog.h"

OpenFileDialog::OpenFileDialog( wxFrame *       parent)
: wxFileDialog( parent,
               L"Choose a file",
               ::wxGetHomeDir(),              // home directory
               L"",                // initial file name
               L"GEDCOM files (*.ged)|*.ged;*.GED",
               wxFD_FILE_MUST_EXIST | wxFD_CHANGE_DIR)
{
    wxString        dftDir = ::wxGetHomeDir();
    std::wcerr << "std::getenv(\"HOME\")=" << dftDir.c_str() << "\n";
    
    std::wcerr << "start: GetDirectory()=" << GetDirectory().c_str()
    << ", GetFilename()=" << GetFilename() << "\n";
    std::wcerr << "start: GetWildcard()=" << GetWildcard().c_str() << "\n";
    std::wcerr << "SetDirectory(" << dftDir.c_str() << ")\n";
    SetDirectory(dftDir);
    
    // get configuration for dialog
    wxString        lastFn  = L"/media/disk-1/Documents and Settings/Jim Cobban/My Documents/FamilyTree/Cobban.GED";
    std::wcerr << "lastFn=" << lastFn.c_str() << "\n";
    size_t    endDir    = lastFn.find_last_of('/', lastFn.length() - 1);
    std::wcerr << "endDir=" << endDir << ", length=" << lastFn.length() << "\n";
    if (endDir == std::string::npos)
    {                     // no directory separator
    std::wcerr << "SetFilename(" << lastFn.c_str() << ")\n";
    SetFilename(lastFn);
    }                     // no directory separator
    else
    {                     // directory separator present
    wxString        directory, filename;
    directory       = lastFn.substr(0, endDir);
    filename        = lastFn.substr(endDir + 1);
    std::wcerr << "SetDirectory(" << directory.c_str() << ")\n";
    SetDirectory(directory);
    std::wcerr << "SetFilename(" << filename.c_str() << ")\n";
    SetFilename(filename);
    std::wcerr << "last: GetDirectory()=" << GetDirectory().c_str()
    << ", GetFilename()=" << GetFilename().c_str() << "\n";
    }                     // directory separator present
    std::wcerr << "return: GetDirectory()=" << GetDirectory().c_str()
    << ", GetFilename()=" << GetFilename().c_str() << "\n";
    }              //  OpenFileDialog::OpenFileDialog
    
    //****************************************
    //
    //  OpenFileDialog::~OpenFileDialog
    //
    //  Destructor.  Release child resources.
    //
    //****************************************
    OpenFileDialog::~OpenFileDialog()
    {
    
    }                     //  OpenFileDialog::~OpenFileDialog
    
    GenFrame::GenFrame( )
    : wxFrame( (wxFrame*) NULL,
    -1,
    L"Test Driver",
    wxPoint(50, 50),
    wxSize(500, 500) )
    {
    // allocate and initialize the open file dialog
    OpenFileDialog * openFileDialog = new OpenFileDialog(this);
    if (openFileDialog->ShowModal() == wxID_OK){
    wxString fileName = openFileDialog->GetPath();
    }
    
    }       //  GenFrame::GenFrame
    
    GenFrame::~GenFrame()
    {
    }       //  GenFrame::~GenFrame
    
    IMPLEMENT_APP(GenTool)
    
    //****************************************
    //
    //  GenTool::OnInit
    //
    //  Method called when GUI initialization complete.
    //
    //****************************************
    bool GenTool::OnInit()
    {
    // create an instance of the main window
    GenFrame *frame = new GenFrame();
    
    // display the window as the top window for this application
    std::cerr << "frame->Show(TRUE);\n";
    frame->Show(TRUE);
    SetTopWindow(frame);
    
    // continue in the event loop
    return TRUE;
} 
And got the following output :

Code: Select all


[Session started at 2009-06-17 20:31:25 -0400.]
std::getenv("HOME")=/Users/mmg
start: GetDirectory()=/Users/mmg, GetFilename()=0x152a9c
start: GetWildcard()=GEDCOM files (*.ged)|*.ged;*.GED
SetDirectory(/Users/mmg)
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()=/media/disk-1/Documents and Settings/Jim Cobban/My Documents/FamilyTree, GetFilename()=Cobban.GED
return: GetDirectory()=/media/disk-1/Documents and Settings/Jim Cobban/My Documents/FamilyTree, GetFilename()=Cobban.GED
frame->Show(TRUE);

The Debugger has exited with status 0.
Which I believe is the expected output?
"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 » Thu Jun 18, 2009 2:08 am

Auria wrote:Hmm not sure what's up with your quotes ("), they're all messed up
I apologize. I should have attached the two files rather than trying to imbed them in the posting. The functionality of the

Code: Select all

 tag seems to unescape escaped quotes when it displays the code.

[quote="Auria"]
And got the following output :

[code]

[Session started at 2009-06-17 20:31:25 -0400.]
std::getenv("HOME")=/Users/mmg
start: GetDirectory()=/Users/mmg, GetFilename()=0x152a9c
start: GetWildcard()=GEDCOM files (*.ged)|*.ged;*.GED
SetDirectory(/Users/mmg)
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()=/media/disk-1/Documents and Settings/Jim Cobban/My Documents/FamilyTree, GetFilename()=Cobban.GED
return: GetDirectory()=/media/disk-1/Documents and Settings/Jim Cobban/My Documents/FamilyTree, GetFilename()=Cobban.GED
frame->Show(TRUE);

The Debugger has exited with status 0.
Which I believe is the expected output?[/quote]

So if it works on your system, why doesn't it work on mine? I have the latest stable version of wxWidgets, I just downloaded it last week. I am running Ubuntu 9.04 with Gtk 2.

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

Post by jamescobban » Thu Jun 18, 2009 2:23 am

doublemax wrote:GetFilename() and SetFilename() are simple getters and setters, i just can't think of anything going wrong there.

I noticed that the "correct" output is given when you print a string directly, but not when you use the return value from a method.

I suspect it's just a display problem with std::

Could you test this code please:

Code: Select all

wxString dftDir = ::wxGetHomeDir();
std::wcerr << "dftDir="" << dftDir.c_str() << ""\n";
std::wcerr << "wxGetHomeDir()="" << ::wxGetHomeDir().c_str() << ""\n";

[/quote]

I don't understand your point.  I believe that the fact that stream insertion is not well supported by wxWidgets is irrelevant.  In my example code some attributes of wxFileDialog are initialized using string literals, and when I print the result of calling the GetXxx method for those attributes I get the value which I specified when I issued SetXxx.  But if I call the SetXxx method with an instance of wxString, and then print the result of GetXxxx I get the default value for the attribute, and the behavior of the dialog is consistent with the values of the attributes as displayed by GetXxxx.

I don't want to use the wxLog methods because they are not type safe.  That is why the stream inserters were added to C++ in the first place.

I consider it a bug that in the Unicode version of wxWidgets inserting a wxString into an output stream displays an address in hex, whereas in the Ansi version the string value of the wxString is displayed.  That is I only have to call the c_str() method before inserting into a stream in the Unicode version (although it is safe to call it in both cases).

DavidHart
Site Admin
Site Admin
Posts: 4019
Joined: Thu Jan 12, 2006 6:23 pm
Location: IoW, UK

Post by DavidHart » Thu Jun 18, 2009 12:12 pm

Hi,

Auria's code failed for me, using wxGTK-2.8.10. That's because of what seems to be a bug in (the wxGTK) wxFileDialog::SetFilename, which asserts if you pass it a filepath; but gtk requires one, and if you pass a filename gtk asserts and doesn't properly create the dialog. I'll look into this.

If I pass a valid filepath (and ignore the assert), std::wcerr << "return: GetDirectory()=" gives the correct output, though the GetFilename() doesn't, of course. However for you, neither works. Are you getting a gtk assert? (Are you using a wx debug build?)

I wonder if some of the problem is going to be a version of the transient buffer problem described in http://wiki.wxwidgets.org/WxString#Conv ... mal_String. The race condition that this causes would explain why the code works for other people.

Regards,

David

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

Post by jamescobban » Thu Jun 18, 2009 5:45 pm

DavidHart wrote:Hi,

Auria's code failed for me, using wxGTK-2.8.10. That's because of what seems to be a bug in (the wxGTK) wxFileDialog::SetFilename, which asserts if you pass it a filepath; but gtk requires one, and if you pass a filename gtk asserts and doesn't properly create the dialog. I'll look into this.

If I pass a valid filepath (and ignore the assert), std::wcerr << "return: GetDirectory()=" gives the correct output, though the GetFilename() doesn't, of course. However for you, neither works. Are you getting a gtk assert? (Are you using a wx debug build?)

Regards,

David
I figured I would need to get around to this, so I just rebuilt wxWidgets with ../configure --with-gtk --enable-unicode --enable-debug --enable-debug_gdb.

I recompiled and rebuilt my programs. Now when I try to run (or gdb) the program I get "/home/jcobban/workspace/DebugWxFileDialog/Debug/DebugWxFileDialog: error while loading shared libraries: libwx_gtk2ud_richtext-2.8.so.0: cannot open shared object file: No such file or directory"

I haven't even put a richtext widget in the app (although I will once I get past this problem with the file dialog).

DavidHart
Site Admin
Site Admin
Posts: 4019
Joined: Thu Jan 12, 2006 6:23 pm
Location: IoW, UK

Post by DavidHart » Thu Jun 18, 2009 6:45 pm

It's a *buntu speciality. See http://forums.wxwidgets.org/viewtopic.php?t=11734 (and, if you want a thorough explanation, http://www.dwheeler.com/program-library ... O/x36.html).
I haven't even put a richtext widget in the app
It seems to be random which lib gets mentioned in the error message.

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

Post by jamescobban » Thu Jun 18, 2009 7:42 pm

DavidHart wrote:It's a *buntu speciality. See http://forums.wxwidgets.org/viewtopic.php?t=11734 (and, if you want a thorough explanation, http://www.dwheeler.com/program-library ... O/x36.html).
Silly me, I forgot to run ldconfig after make install.

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

Post by jamescobban » Thu Jun 18, 2009 9:20 pm

DavidHart wrote:Hi,

If I pass a valid filepath (and ignore the assert), std::wcerr << "return: GetDirectory()=" gives the correct output, though the GetFilename() doesn't, of course. However for you, neither works. Are you getting a gtk assert? (Are you using a wx debug build?)
I have rebuilt wxWindows with debug and tried running the program. Tracing the logic I cannot see what is going wrong. It seems to be calling the right methods in Gtk, but it just isn't working. I don't see any asserts.

For example the constructor wxFileDialog::wxFileDialog follows the execution path that I would expect because I have put a non-empty string for the default directory and an empty string for the file name in the constructor. I see the constructor execute the following statements:

Code: Select all

wxFileName fn;
fn.AssignDir(defaultDir);
const wxString dir = fn.GetPath();
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(m_widget),
                       dir.fn_str());

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

Post by Auria » Fri Jun 19, 2009 5:13 pm

Coming back with an old comment I made that you didn't seem to appreciate ;) What if you test with a path that is not outside the linux filesystem? It may well be that gtk_file_chooser_set_current_folder doesn't like foreign filesystems.

In any case, GTK+ docs (http://library.gnome.org/devel/gtk/unst ... ent-folder) mention that this method returns a boolean, maybe check it
"Keyboard not detected. Press F1 to continue"
-- Windows

DavidHart
Site Admin
Site Admin
Posts: 4019
Joined: Thu Jan 12, 2006 6:23 pm
Location: IoW, UK

Post by DavidHart » Sat Jun 20, 2009 11:44 am

OK, see http://trac.wxwidgets.org/ticket/10917

James, as you can see, the wxGTK wxFileDialog getters/setters are buggy; so it wasn't an output problem, just that the getters were returning "".

wxMSW and wxMac use the generic dialog, which doesn't have this problem.

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

Post by jamescobban » Sat Jun 20, 2009 10:08 pm

DavidHart wrote:OK, see http://trac.wxwidgets.org/ticket/10917

James, as you can see, the wxGTK wxFileDialog getters/setters are buggy; so it wasn't an output problem, just that the getters were returning "".

wxMSW and wxMac use the generic dialog, which doesn't have this problem.
Thanks for investigating this. I have only just started on using wxWidgets, so what is the procedure for applying your fix to my copy of the source?

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

Post by Auria » Sat Jun 20, 2009 10:29 pm

Take a look at 'man patch', or google for how to apply a patch ;) e.g. http://www.linuxhq.com/patch-howto.html
"Keyboard not detected. Press F1 to continue"
-- Windows

Post Reply