Board index » cppbuilder » TOpenDialog and Filter for NO extension

TOpenDialog and Filter for NO extension


2006-06-30 03:11:54 AM
cppbuilder81
Hello,
I have been searching without luck for a way to get the TOpenDialog file
list to show | only files with no extension |.
This is required for my application - the file selected must have no
extension (no period or anything beyond), so it would be nice to show only
files having no extension.
No filter settings work - i.e.
in policy.h: TOpenDialog *OpenPolicy;
in policy.csl on a menu item file->open click:
OpenPolicy->Options << ofEnableIncludeNotify; // added for
OpenPolicyIncludeItem function support
OpenPolicy->Filter = "Policy MUST have no ext (*.)|*.|All Files (*.*)|*.*";
// does nothing but prevent anything from being displayed.
OpenPolicy->FilterIndex = 1; // start the dialog showing no extension files
OpenPolicy->Execute();
... additional code to open file
Switching to ofOldStyleDialog=true works! but opens with the wrong intial
dir and is inconsistent with the application (all other dialogs in the app
are the normal new kind -would be nice to use the new dialog).
Searching, I found references to OnIncludeItem and that it could be used to
filter - wrote this code - it seems to work (in the de{*word*81}) but the
Include value does Nothing to the resulting dialog (setting it to False has
no affect on the display). I also saw some page somewhere that said
OnIncludeItem is no longer supported - but I am running C++ Builder 5.0 and
it is in the help with no mention of 'obsolete' as some other functions in
help show.
Debugging shows this routine Does get hit and shows each filename - setting
Include= correctly for design -but it does nothing to resulting dialog.
// OnIncludeItem sample:
<code/>
void __fastcall TITRRecordForm::OpenPolicyIncludeItem(
const TOFNotifyEx &OFN, bool &Include)
{
/* masking code:
char Path[256];
AnsiString FileName;
if( SHGetPathFromIDList( (LPCITEMIDLIST)OFN.pidl, Path ) )
{
FileName = AnsiStrRScan( Path, '\\' ) + 1; // remove path
// look for extension
if (FileName.AnsiPos('.')==0)
{
// no period = no extension
Include = True;
}
else
{
Include = False;
}
}
*/
// OR tried to block them all - no affect
Include = False; // or Include=false; with no filter set - should show
nothing, shows all files
// OR
// Include = True; // with a Filter = "*."; // shows all files
}
</code>
Any suggestions???
Thanks,
Todd
 
 

Re:TOpenDialog and Filter for NO extension

"Todd" < XXXX@XXXXX.COM >wrote in message
Quote
I have been searching without luck for a way to get the
TOpenDialog file list to show | only files with no extension |.
Use the OnIncludeItem event for custom filtering.
Quote
the Include value does Nothing to the resulting dialog (setting it
to False has no affect on the display).
Did you verify that the event handler is being called in the first place?
Quote
I also saw some page somewhere that said OnIncludeItem is
no longer supported - but I am running C++ Builder 5.0 and it
is in the help with no mention of 'obsolete' as some other functions
in help show.
It is not a matter of VCL support. OnIncludeItem is based on
CDN_INCLUDEITEM notifications that the OS sends to the dialog. If the OS
does not support those notifications anymore (and there is no indication on
MSDN of that), then the event would be ignored.
However, MSDN does say the following:
"The dialog box always includes items that have both the
SFGAO_FILESYSTEM and SFGAO_FILESYSANCESTOR attributes, regardless of the
value returned by CDN_INCLUDEITEM."
If that is what is actually happening, then short of hijacking the ListView
of the dialog and removing the items manually, you will just have to
validate the FileName manually, either after the dialog closes, or in the
dialog's OnCanClose event.
Quote
FileName = AnsiStrRScan( Path, '\\' ) + 1; // remove path
// look for extension
if (FileName.AnsiPos('.')==0)
Use ExtractFileName() and/or ExtractFileExt() instead.
Gambit
 

Re:TOpenDialog and Filter for NO extension

Responses below - please read and reply...
"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote

"Todd" < XXXX@XXXXX.COM >wrote in message
news:44a425f8$ XXXX@XXXXX.COM ...

>I have been searching without luck for a way to get the
>TOpenDialog file list to show | only files with no extension |.

Use the OnIncludeItem event for custom filtering.

This is my point - this event does nothing when called
Quote
>the Include value does Nothing to the resulting dialog (setting it
>to False has no affect on the display).

Did you verify that the event handler is being called in the first place?

YES - it is called, and as I stated - it steps through but setting the
Include value to either True, true, False or false does NOTHING - no affect
to the file list box is seen - file names that get a 'False' ARE still shown
in the box along with the values that get a 'True'.
Quote
>I also saw some page somewhere that said OnIncludeItem is
>no longer supported - but I am running C++ Builder 5.0 and it
>is in the help with no mention of 'obsolete' as some other functions
>in help show.

It is not a matter of VCL support. OnIncludeItem is based on
CDN_INCLUDEITEM notifications that the OS sends to the dialog. If the OS
does not support those notifications anymore (and there is no indication
on
MSDN of that), then the event would be ignored.

However, MSDN does say the following:

"The dialog box always includes items that have both the
SFGAO_FILESYSTEM and SFGAO_FILESYSANCESTOR attributes, regardless of the
value returned by CDN_INCLUDEITEM."

If that is what is actually happening, then short of hijacking the
ListView
of the dialog and removing the items manually, you will just have to
validate the FileName manually, either after the dialog closes, or in the
dialog's OnCanClose event.

>FileName = AnsiStrRScan( Path, '\\' ) + 1; // remove path
>// look for extension
>if (FileName.AnsiPos('.')==0)

Use ExtractFileName() and/or ExtractFileExt() instead.

I do not understand what you are saying, sounds like you think my event
handler code does not work - the OnIncludeItem event handler does get
called - and my code Does parse and identify valid files. Tthe
ExtractFileExt() might be better to use - but it will not fix the problem.
The event handler, shown in my sample code as OpenPolicyIncludeItem(..) was
inserted by the Object Viewer event handler for OnIncludeItem (when I
double-clicked this event, Borland inserted this function in my code)).
Problem is - ***the standard TOpenDialog box file list is not affected by
the Include variable value*** - and the filter property does NOT accept *.
as a valid value - using it blocks ALL files.
Only setting the flag ofOldStyleDialog=true for the dialog box works!
I should not have to use the 'older' style box -
This post describes TWO BUGs in TOpenDialog!
1) *. does not work in the new style dialog 'Filter'
2) the Include value returned by the OnIncludeItem event does nothing to
the file passed in - it shows the file name in the Dialog list regardless of
the 'Include' value.
Todd
Quote

Gambit


 

{smallsort}

Re:TOpenDialog and Filter for NO extension

"Todd" < XXXX@XXXXX.COM >wrote in message
Quote
I do not understand what you are saying
All I said was that you would have to use the OnCanClose event, or wait for
the Execute() to return, to validate the FileName manually. And that rather
than using AnsiStrRScan() and AnsiPos(), you can use ExtractFileExt()
instead. That sounds very clear to me. For example:
void __fastcall TITRRecordForm::OpenPolicyCanClose(TObject* Sender, bool
&CanClose)
{
AnsiString Ext = ExtractFileExt(OpenPolicy->FileName);
CanClose = Ext.IsEmpty();
if( !CanClose )
Application->MessageBox("Please choose only files that have no
extensions", "Invalid file", MB_OK);
}
Quote
sounds like you think my event handler code does not work
I told you that it doesn't. MSDN states that the dialog always includes
items from the file system regardless of what the OnIncludeItem event says.
Besides that, your original code was not using SHGetPathFromIDList()
correctly anyway. The ITEMIDLIST that is provided is relative to the folder
whose items are being displayed. When the OFN.psf member is no NULL, you
must type-cast it to an IShellFolder pointer and then use
IShellFolder::GetDisplayNameOf() to translate the ITEMIDLIST into a string.
SHGetPathFromIDList() only works on absolute ITEMIDLISTs, not relative ones.
For example:
#include <shlwapi.h>// add shlwapi.lib to the project as well
void __fastcall TITRRecordForm::OpenPolicyIncludeItem(const TOFNotifyEx
&OFN, bool &Include)
{
char buf[MAX_PATH+1] = {0};
LPITEMIDLIST pidl = static_cast<LPITEMIDLIST>(OFN.pidl);
if( OFN.psf )
{
IShellFolder *pSF = static_cast<IShellFolder*>(OFN.psf);
ULONG attrs = 0;
if( SUCCEEDED(pSF->GetAttributesOf(1,
const_cast<LPCITEMIDLIST*>(&pidl), &attrs)) )
{
if( attrs & SFGAO_FILESYSTEM )
{
if( attrs & SFGAO_FILESYSANCESTOR )
{
Include = true;
return;
}
if( (attrs & SFGAO_FOLDER) == 0 )
{
STRRET str = {0};
if( SUCCEEDED(pSF->GetDisplayNameOf(pidl,
SHGDN_FORPARSING, &str)) )
StrRetToBuf(&str, pidl, buf, MAX_PATH+1);
}
}
}
}
else
SHGetPathFromIDList(pidl, buf);
Include = ((buf[0] != '\0') && ExtractFileExt(buf).IsEmpty());
}
Alternatively:
#include <shlwapi.h>// add shlwapi.lib to the project as well
void __fastcall TITRRecordForm::OpenPolicyIncludeItem(const TOFNotifyEx
&OFN, bool &Include)
{
LPITEMIDLIST pidl = static_cast<LPITEMIDLIST>(OFN.pidl);
IShellFolder *pSF;
if( OFN.psf )
pSF = static_cast<IShellFolder*>(OFN.psf);
else
SHGetDesktopFolder(&pSF);
if( pSF )
{
ULONG attrs = 0;
if( SUCCEEDED(pSF->GetAttributesOf(1,
const_cast<LPCITEMIDLIST*>(&pidl), &attrs)) )
{
if( attrs & SFGAO_FILESYSTEM )
{
if( attrs & SFGAO_FILESYSANCESTOR )
{
Include = true;
return;
}
if( (attrs & SFGAO_FOLDER) == 0 )
{
STRRET str = {0};
char buf[MAX_PATH+1] = {0};
if( SUCCEEDED(pSF->GetDisplayNameOf(pidl,
SHGDN_FORPARSING, &str)) )
StrRetToBuf(&str, pidl, buf, MAX_PATH+1);
Include = ((buf[0] != '\0') &&
ExtractFileExt(buf).IsEmpty());
}
}
}
if( !OFN.psf )
pSF->Release();
}
}
Now, with that said, the above will not solve your problem at all. Even
when using IShellFolder properly, you still can't filter out items that are
part of the file system anyway. The dialog will still add them regardless
of what the OnIncludeItem event handler says. So it won't matter if items
have extensions or not.
Quote
the OnIncludeItem event handler does get called - and my code Does
parse and identify valid files. Tthe ExtractFileExt() might be better to
use - but it will not fix the problem.
Yes, it will. You just have to use it in a different place. See the first
example above.
Quote
Problem is - ***the standard TOpenDialog box file list is not
affected by the Include variable value***
I already explained that to you.
Quote
This post describes TWO BUGs in TOpenDialog!
They are not bugs. TOpenDialog is a simple wrapper around the OPENFILENAME
dialog from the Win32 API. All of the dilog's functionality is controlled
by the OS, not the VCL. Microsoft is very specific in documenting the
capabilities of that dialog.
It is not possible to automate the filtering of files with no extensions,
unless you write your own custom dialog from scratch. "*." is a DOS filter,
not a Windows filter. And the CDN_INCLUDEITEM notification does not apply
to file system items. You will just have to show everything, and then
validate the user's selection before using it. The native dialog simply
does not support what you are asking for.
Gambit
 

Re:TOpenDialog and Filter for NO extension

Thanks Gambit,
I appreciate the help - I am a 6-month MS VS2003.NET, 4 year VS6.0 DOS,
ZINC, plus a bit of siimple Borland 4.52 maintenance a long time
ago...developer guy who just got hired to a job using Borland 5.0... and it
is really a new learning curve. (Especially since Borland does not have a
lot of example code in the help file and not as many web-sites).
I did find a solution- since the old dialog box does correctly filter by
"*." it will work - asked and management didn't really mind using the old
style.
I set the Initial directory field (using my sample code below), and in the
Object viewer, set the ofOldStyleDialog = true and that was all that was
needed. This older style box does correctly filter and shows only the files
in the directory with no extension. It is too bad MS dropped support for
extension less filter design in the newer dialog.
I pulled the OnIncludeItem stuff since it does nothing as you said.
The AnsiStrRScan() was part of an example I found in a Google borland group
example - kindof a neat to reverse crop by picked char - in the end, I had
to write some simple code as the string set I parsed to get the path from
was a string of comma delimited strings with \" quotes (from the registry),
something like:
"\"C:\\\\dir\\subdir\\filename.abc\",\"C:\\\\secondir\\subdir\\filename2.abc..."
with many more string sets for total of over 600 characters - maybe a faster
way, but this worked...
//...in code....
AnsiString szDir = GetPolicyDir();
OpenPolicy->InitialDir = szDir;
#include <Registry.hpp>
AnsiString __fastcall TRecordForm::GetPolicyDir()
{
AnsiString szDir="";
TRegistry *Registry = new TRegistry;
int iIndex;
try
{
try
{
Registry->RootKey = HKEY_CURRENT_USER;
// false because we do not want to create it if it doesn't exist
Registry->OpenKey("SOFTWARE\\CompanyName\\\Product\\Prefs",
false);
szDir = Registry->ReadString("RecentPolicyfiles");
if (szDir.Length()>5)
{
int iIndex = szDir.Pos(",\""); // find break
after first full path/filename
szDir = szDir.SubString(2, iIndex-3); // pull first
c:\\path\\filename from group
iIndex = szDir.LastDelimiter('\\'); // find start of
filename
szDir = szDir.SubString(1, iIndex); // remove filename
szDir = szDir + "Dataset\\fonts"; // add path where
extension-less file is located
}
}
catch (const EAccessViolation &e)
{
String err = e.Message; // use e to pass var defined but not
used warnings
szDir = "";
}
}
__finally
{
delete Registry;
}
return szDir;
}
I know, not much, but I felt a bit overwhelmed with your sample code - had
to put something in here (<grin>Thanks - nice to find a forum where I can
actually get some help!).
Maybe someone will like my quick registry access code example since the ones
in the help file are not very easy to read. Quite a bit easier than regular
registry calls for which there was no sample code.
Borland stuff is so different:
LPITEMIDLIST pidl = static_cast<LPITEMIDLIST>(OFN.pidl);
static_cast and <>are delimiters I have yet to learn, though I saw them
pop-up in VS2005 which I just started playing with.
Thanks,
Todd
 

Re:TOpenDialog and Filter for NO extension

Maybe there's something of use to you here Todd (I've been on vacation
the last two weeks.) Note that population of the OpenDialog listview
window can be very slow when there are hundreds of files to be scanned
or added.
home.att.net/~secondcut/opdlglv.htm
Tim
"Todd" < XXXX@XXXXX.COM >wrote in message
Quote
Thanks Gambit,
I appreciate the help - I am a 6-month MS VS2003.NET, 4 year VS6.0