ShellPlus Customer login
ShellPlus
Shell+ components
    Home
    News
    Overview
    Download
    Examples
    Customer's area
    Flash Demo
 
Developer Tools
    Shell Reset Tool
 
Shell+ Tutorial
    Namespace Extensions
    ShortCut menu
    Property Sheet
    Icon Handler
    Thumbnails
    InfoTip Handler
    Copy Hook
    Balloon TrayIcon
    Control Panel
    Shortcut Files
    Drag&Drop Menu
    Shell Change Notify
 
 
Documents
    Articles Index
    Press Releases
 
Purchase
    Buy now
    Resellers network
    Resellers wanted
 
Support
    Contact directly
    Customer's area
 
About/Contacts
    Shell+ Developers

Embarcader Technology Partner

 

Writing data handling events for DataProvider

When you implement the namespace extension almost all code you need to write is DataProvider events. DataProvider is the most important component inside your NSE, it is a connecting layer between your business logic and Windows Shell.

This article will describe how to use different data providers and their principles of handing their common events. You can download examples for this article by the following link: http://www.shellplus.com/examples/namespace-extension-example.html

How to use data providers

Three DataProviders are available now: TSxSimpleTreeProvider, TSxByHandProvider and TSxDataSetProvider. To help in your choice we'll explain key differences in using of each DataProvider:

TSxByHandProvider is the most flexible and powerful data provider, but you need to write a bit more code than with other providers ;-) Any of data storage can be a source for your items and folders: remote database, hidden folder on your hard disk, xml page on web server. Even some calendar generated in runtime can be used for this purpose.

If you work with TSxByHandProvider you should implement OnPopulate event to provide data from your custom data storage. It is a common example:

procedure TSxPermanentModule1.ByHandProviderPopulate(
  Sender: TSxByHandProvider; DataGrain: TSxByHandDataGrain;
  GrainList: TList);
var
  TempFolder:String;
  SearchRec:TSearchRec;
  TempGrain:TSxCustomDataGrain;
begin
  if DataGrain.IsRoot then
     TempFolder:='C:\'
  else
  begin
    DataGrain.Data.Seek(0,0);
    TempFolder:=DataGrain.SxData.ReadString;
  end;
  if FindFirst(IncludeTrailingBackSlash(TempFolder)+'*',faAnyFile,SearchRec)=0 then
  try
    repeat
      if (SearchRec.Name='.') or (SearchRec.Name='..') then
         Continue;
      if (SearchRec.Attr and faDirectory)<>faDirectory then
         Continue;
      TempGrain:=Sender.CreateGrainInstance;
      TempGrain.Name:=SearchRec.Name;
      TempGrain.GrainType:=gtFolder;
      TempGrain.SxData.WriteString(IncludeTrailingBackslash(TempFolder)+SearchRec.Name);
      GrainList.Add(TempGrain);
    until FindNext(SearchRec)<>0;
  finally
    SysUtils.FindClose(SearchRec);
  end;

  if FindFirst(IncludeTrailingBackSlash(TempFolder)+'*',faAnyFile,SearchRec)=0 then
  try
    repeat
      if (SearchRec.Name='.') or (SearchRec.Name='..') then
         Continue;
      if (SearchRec.Attr and faDirectory)=faDirectory then
         Continue;
      TempGrain:=Sender.CreateGrainInstance;
      TempGrain.Name:=SearchRec.Name;
      TempGrain.GrainType:=gtItem;
      TempGrain.SxData.WriteString(IncludeTrailingBackslash(TempFolder)+SearchRec.Name);
      GrainList.Add(TempGrain);
    until FindNext(SearchRec)<>0;
  finally
    SysUtils.FindClose(SearchRec);
  end;
end;

As you see above, we provide a list of DataGrains that belongs to the folder specified by DataGrain parameter.

First you check whether specified folder is a root of your namespace. If not, you work with it in a way that was used to create it. It is so because all data grains you work with inside of your NSE was produced by the same event handler.

After that you compose a list of DataGrains (contents of required folder) to the GrainList parameter. You should keep some unique key (e.g. ID) inside the DataGrain to link it with your data inside the custom storage. In our case it is just a full qualified path to the file or folder.

 

TSxSimpleTreeProvider is the most simple data provider of currently available providers. It keeps a tree mapped namespace inside. You can specify its contents in design time or in runtime. You can load and save tree data from/to file or stream and does not need to implement OnPopulate event (it does not have it).

Simple Tree Editor window (design time)

 

TSxDataSetProvider designed to simplify work with DB-related data. E.g. you can put TClientDataSet, TDataSource and any MIDAS provider on the SxPermanentModule and link them using corresponding properties. As a result you get a thin client for three-tier system.

TSxDataSetProvider have a few specific properties to setup the data processing engine:

GrainSetup Contains settings to setup the tree data processing engine
RootKeyID Specifies an unique value, that should be used to determine root of displayed tree.

RootKeyID is a simple variant property, but GrainSetup property requires more explanation:

FileClosedIconField Contains the name of field, which value should be used as closed file icon*.
FileClosedIconSubstitution Contains rules for transforming field values to closed file icon indices.
FileOpenIconField Contains the name of field, which value should be used as open file icon*.
FileOpenIconSubstitution Contains rules for transforming field values to open file icon indices.
FolderClosedIconField Contains the name of field, which value should be used as closed folder icon.
FolderClosedIconSubstitution Contains rules for transforming field values to closed folder icon indices.
FolderOpenIconField Contains the name of field, which value should be used as open folder icon.
FolderOpenIconSubstitution Contains rules for transforming field values to open folder icon indices.
GrainNameField Contains the name of field, which value should be used as corresponding grain name.
GrainTypeField Contains the name of field, which value should be used as corresponding grain type.
GrainTypeSubstitution Contains rules for transforming field values to grain types.
ParentKeyField Contains the name of field, which values should be used as reference value to the parent folder.
PrimaryKeyField Contains the name of field, which values should be used as primary key in database.

The ParentKeyField should be a reference to PrimaryKeyField and your data should have at least the following format:

PrimaryID
ParentID
GrainName
GrainType
1
0
Root Folder
1
2
1
First Folder
1
3
1
Second Folder
1
4
2
Item in FirstFolder
2
5
3
Item in SecondFolder
2

Handling of DataProvider common events

The rest of DataProvider events and properties related to clipboard and drag'n'drop operations. This events are based on parent to all data providers class and only difference - we will cast custom classes, that we retrieve as event handler parameters, to classes specific for our project. We'll use TSxSimpleProvider for examples.

There are two types of common data handing events:

In the Windows Shell data transfer scenarios (MSDN) mentioned many different data formats, and all these formats are supported by Shell+. Every event group has events for every data format, so you can implement any or even all of them. E.g. if your namespace extension is ready only (it should not accept files) you can implement only "source" events, or if you namespace extension should support drag'n'drop items only between folders inside the same namespace, you can implement only private format support events.

 
OnDataGrainDrop
not required
OnNewGrainFromStream OnGetGrainFileInfo
OnGetGrainFileContents
OnNewGrainFromFile
OnNewGrainFromStream
OnGetGrainFileName
not implemented
not required

OnHandleModify
OnNewGrainFromFile
OnNewGrainFromStream
OnHandleDelete

OnGetGrainFileName
OnGetGrainFileContents
OnGetGrainFileInfo

 

Target events group is a set of events, that allows you accept files from drag'n'drop, copy/paste operations and in several other cases.

 

OnDataGrainDrop event called when user has dropped object on your NSE and source of this object does support Private data format. Always the source is the same NSE.

You receive dropped object representation (DataGrain parameter) and representation of the folder, where new object was dropped (FolderGrain parameter).

procedure TPermanentModule.SxSimpleTreeProviderDataGrainDrop(
  Sender: TSxCustomProvider; FolderGrain, DataGrain: TSxCustomDataGrain);
var
  PermanentFolder:TSxSimpleTreeDataGrain;
  NewGrain:TSxSimpleTreeDataGrain;
begin
  PermanentFolder:=TSxSimpleTreeProvider(Sender).
                          LocatePermanentGrain(TSxSimpleTreeDataGrain(FolderGrain).GUID); PermanentFolder.CreateNewChild(NewGrain); PermanentFolder.Add(NewGrain); NewGrain.Name:=DataGrain.Name; NewGrain.GrainType:=DataGrain.GrainType; SxSimpleTreeProvider.NotifyAddGrain(FolderGrain,NewGrain); end;

 

OnNewGrainFromStream event called when user has dropped object on your NSE and source of this object does support CFSTR_FILECONTENTS or CFSTR_HDROP data format or file was saved from Common Dialog to your NSE. There are many applications allow support this data format.

You receive a folder, where new object was dropped (FolderGrain), file information descriptor (FileInfo) and file data stream (FileData). Just create a new data grain, whose parent is FolderGrain and fill your storage with data for new grain.

procedure TPermanentModule.SxSimpleTreeProviderNewGrainFromStream(
  Sender: TSxCustomProvider; FolderGrain: TSxCustomDataGrain;
  FileInfo: TSxFileInfoDescriptor; FileData: TStream);
var
  Temp:array [0..1000] of char;
  Size:Integer;
  PermanentFolder:TSxSimpleTreeDataGrain;
  NewGrain:TSxSimpleTreeDataGrain;
begin
  Size:=Min(1000,FileData.Size);
  FillChar(Temp,1000,#0);
  FileData.Read(Temp,Size);
  PermanentFolder:=TSxSimpleTreeProvider(Sender).
                     LocatePermanentGrain(TSxSimpleTreeDataGrain(FolderGrain).GUID); PermanentFolder.CreateNewChild(NewGrain); PermanentFolder.Add(NewGrain); NewGrain.Name:=StrPas(Temp); NewGrain.GrainType:=gtItem; SxSimpleTreeProvider.NotifyAddGrain(FolderGrain,NewGrain); end;

 

OnNewGrainFromFile event called when user has dropped object on your NSE and source of this object does support CFSTR_HDROP file format or file was saved from Common Dialog to your NSE.

You receive the same FolderGrain and fully qualified path for the source file. You will add new grain to your namespace and fill internal data storage with new file contents.

procedure TPermanentModule.SxSimpleTreeProviderNewGrainFromFile(
  Sender: TSxCustomProvider; FolderGrain: TSxCustomDataGrain;
  FileName: WideString);
var
  PermanentFolder:TSxSimpleTreeDataGrain;
  NewGrain:TSxSimpleTreeDataGrain;
begin
  PermanentFolder:=TSxSimpleTreeProvider(Sender).
                       LocatePermanentGrain(TSxSimpleTreeDataGrain(FolderGrain).GUID); PermanentFolder.CreateNewChild(NewGrain); PermanentFolder.Add(NewGrain); NewGrain.Name:=ExtractFileName(Filename); NewGrain.GrainType:=gtItem; SxSimpleTreeProvider.NotifyAddGrain(FolderGrain,NewGrain); end;

 

OnHandleModify event called when file representation of your data grain was updated by application, where your grain opened through common dialog.

You receive DataGrain that need to be modified (DataGrain property) and its contents in the stream (DataStream property). You need just update your data storage with new contents from stream.

ProcedureTPermanentModule.SxSimpleTreeProviderHandleModify(
  Sender: TSxCustomProvider; DataGrain: TSxCustomDataGrain;
  DataStream: TStream);
var
  ThisPermanentGrain:TSxSimpleTreeDataGrain; // Only TSxSimpleTreeView specific
  Temp:array [0..1000] of char; // Just for example
begin
  if DataStream.Size>1000 then
     Exit;
  FillChar(Temp,1000,0);
  ThisPermanentGrain:=TSxSimpleTreeProvider(Sender).
                        LocatePermanentGrain(TSxSimpleTreeDataGrain(DataGrain).GUID); DataStream.Read(Temp,DataStream.Size); ThisPermanentGrain.Name:=StrPas(Temp); end;

 

OnHandleDelete event called when file representation of your data grain was deleted. You can handle this event by the following way:

procedure TPermanentModule.SxSimpleTreeProviderHandleDelete(
  Sender: TSxCustomProvider; DataGrain: TSxCustomDataGrain);
begin
  TSxSimpleTreeProvider(Sender).DeletePermanentGrain(DataGrain);
end;

 

Source events group is a set of events, that allows your users to drag, copy and cut data grains from your NSE to another sources (Explorer, Recycle Bin, Outlook etc.)

OnGetGrainFileInfo event called when your NSE or other application need to receive some brief information on your file.

ProcedureTPermanentModule.SxSimpleTreeProviderGetGrainFileInfo(
  Sender: TSxCustomProvider; DataGrain: TSxCustomDataGrain;
  var FileInfo: TSxFileInfoDescriptor);
begin
  FileInfo.FileName:=DataGrain.Name;
  FileInfo.FileSize:=Length(DataGrain.Name);
end;

 

OnGetGrainFileContents event called almost ever after OnGetGrainFileInfo event. You should provide calling side with your data grain contents (from your data storage). This data should be exact contents of the result file.

ProcedureTPermanentModule.SxSimpleTreeProviderGetGrainFileContents(
  Sender: TSxCustomProvider; DataGrain: TSxCustomDataGrain;
  Stream: TMemoryStream);
var
  Temp:array [0..100] of char;*
begin
  StrPLCopy(@Temp,DataGrain.Name,100);
  Stream.Write(Temp,Length(DataGrain.Name))
end;

* Note: never work with dynamicly allocated strings in the stack, use GetMem or gpMalloc methods.

OnGetGrainFileName event need to be handled when calling application supports HDROP data format and your NSE can provide a fully qualified path to the file, that is a true representation of DataGrain, which you will get from event parameters.

ProcedureTSxPermanentModule1.ByHandProviderGetGrainFilename(
  Sender: TSxCustomProvider; DataGrain: TSxCustomDataGrain;
  var Filename: WideString);
begin
  Filename:=DataGrain.Strings[0];
end;

 

Other events group is a set of events, that used for handing common Shell tasks that does not related to OLE.

OnRenameGrain event exposed when someone makes an attempt to rename grain in your folder. You can allow or discard changes by specifiyng approciate value in the PerformRename property.

procedure TFormPermanentModule.SxSimpleTreeProviderRenameDataGrain(
  Sender: TSxCustomProvider; ParentGrain, DataGrain: TSxCustomDataGrain;
  var NewName: WideString; var PerformRename: Boolean);
var
  permanentGrain:TSxSimpleTreeDataGrain;
begin
  permanentGrain:=TSxSimpleTreeProvider(Sender).
                   LocatePermanentGrain(TSxSimpleTreeDataGrain(DataGrain).GUID); permanentGrain.Name:=NewName; PerformRename:=True; end;

Rename verb always enabled if you have implemented this event and always disabled if not. Also you can control Rename verb availability using OnQueryRenameGrain event.

OnQueryRenameGrain can be handled to enable or disable "Rename" verb for specified data grain. Set AllowRename parameter to True if you allow renaming of this item and to False if not. Note that handling this event is not a rename operation, just Shell need know how to display context menu item or button.

BeforeCompareGrains event called to ask you: can specified grain to be compared by specified column?

OnQueryDeleteGrain event can be called to enable or disable "Delete" verb for specified data grain. This event workin in pair with OnHandleDelete event.

End of article.Go top
Last update December 22, 2011

 


Components | Download | Purchase | Support | About Us
Copyright © 2016 ALDYN Software. All rights reserved.
Copyright © 2001 - 2011 Shell+ Development Group. All rights reserved.