ufiles.pas

来自「FMA is a free1 powerful phone editing to」· PAS 代码 · 共 464 行

PAS
464
字号
unit uFiles;

{
*******************************************************************************
* Descriptions: OBEX Files Access
* $Source: /cvsroot/fma/fma/uFiles.pas,v $
* $Locker:  $
*
* Todo:
*
* Change Log:
* $Log: uFiles.pas,v $
*
}

interface

uses
  TntComCtrls, Contnrs, VirtualTrees;

const
  EXTERNAL_PATHSEPERATOR: WideChar = '/';
  INTERNAL_PATHSEPERATOR: WideChar = '\';

  idxFolders: set of byte = [1..3,5..7,19..22,30..35,39..43,46..50,56,57];
  idxFiles: set of byte = [27,36..38,60];

type TIcon = (
       iUnknown = 60,      // unknown file
       iSubDir = 33,       // normal sub dir
       iSoundsDir, {34}    // dir with sounds 
       iImagesDir, {35}    // dir with images
       iMidiFile, {36}     // midi file
       iImageFile, {37}    // image file
       iWaveFile, {38}     // wave file
       iThemeFile = 27);   // theme

     RFileIcon = record
       FileExtension: WideString;
       Icon: TIcon;
     end;

const
  FILEICONS: array [0..10] of RFileIcon = (
    (FileExtension: '.thm';  Icon: iThemeFile),  // do not localize
    (FileExtension: '.amr';  Icon: iWaveFile),   // do not localize
    (FileExtension: '.mp3';  Icon: iWaveFile),   // do not localize
    (FileExtension: '.m4a';  Icon: iWaveFile),   // do not localize
    (FileExtension: '.mid';  Icon: iMidiFile),   // do not localize
    (FileExtension: '.imy';  Icon: iMidiFile),   // do not localize
    (FileExtension: '.gif';  Icon: iImageFile),  // do not localize
    (FileExtension: '.jpg';  Icon: iImageFile),  // do not localize
    (FileExtension: '.png';  Icon: iImageFile),  // do not localize
    (FileExtension: '.wbm';  Icon: iImageFile),  // do not localize
    (FileExtension: '.wbmp'; Icon: iImageFile)); // do not localize

type
  TFileType = (ftDir, ftFile);

  TFile = class(TObject)
  private
    fTreeNode: PVirtualNode;
    fTreeView: TBaseVirtualTree;

    fSize: longword;
    fExternalName: WideString;
    fParent: TFile;
    fDirContents: TObjectList;
    fFileType: TFileType;

    function GetFullPath: WideString;
    function Update: boolean;
    procedure SetTreeNode(const Value: PVirtualNode);
    procedure SetFileType(const Value: TFileType);
    procedure SetSize(const Value: longword);
    function GetInternalName: WideString;
    function GetCount: word;
    function GetDirContent(index: word): TFile;

  public
    constructor Create;
    destructor Destroy; override;

    property InternalName: WideString read GetInternalName;
    property ExternalName: WideString read fExternalName write fExternalName;
    property FullPath: WideString read GetFullPath;
    property FileType: TFileType read fFileType write SetFileType;

    property Size: longword read fSize write SetSize;

    property Parent: TFile read fParent write fParent;
    property TreeNode: PVirtualNode read fTreeNode write SetTreeNode;

    property Count: word read GetCount;
    property DirContent[index: word]: TFile read GetDirContent;
  end;

  TFiles = class(TObject)
  private
    fTreeNode: PVirtualNode;
    fRoot: TFile;
  public
    constructor Create(AOwner: TObject; TreeNode: PVirtualNode);
    destructor Destroy; override;

    function Update: boolean;

    property TreeNode: PVirtualNode read fTreeNode;

    class function FindFileIcon(FileName: WideString): TIcon;
  end;

implementation

uses
  gnugettext, gnugettexthelpers, cUnicodeCodecs,
  SysUtils, TntSysUtils, unit1,   // too bad it needs unit1, this is because obex functionality is still in unit1.pas
  uObex, uXML, WebUtil, ComCtrls, UniTntCtrls, StrUtils;

{ TFile }

constructor TFile.Create;
begin
 fDirContents := TObjectList.Create;
end;

destructor TFile.Destroy;
begin
  fDirContents.Free;

  inherited;
end;

function TFile.GetCount: word;
begin
  result := 0;

  if Assigned(fDirContents) then
    result := fDirContents.Count;
end;

function TFile.GetDirContent(index: word): TFile;
begin
  result := nil;

  if Assigned(fDirContents) and (Index < fDirContents.Count) then
    result := TFile(fDirContents[Index]);
end;

function TFile.GetFullPath: WideString;
var
  CurFile: TFile;
begin
  CurFile := self;

  result := '';
  while assigned(CurFile) do
  begin
    result := CurFile.ExternalName + EXTERNAL_PATHSEPERATOR + result;

    CurFile := CurFile.Parent;
  end;

  if (Length(Result) > 1) and (result[Length(Result)] = EXTERNAL_PATHSEPERATOR) then
    SetLength(Result, Length(Result) - 1);
end;

function TFile.GetInternalName: WideString;
var EData: PFmaExplorerNode;
begin
   result := FullPath;

   result := Tnt_WideStringReplace(result, #13#10, '_', [rfReplaceAll]);
   result := Tnt_WideStringReplace(result, #13, '_', [rfReplaceAll]);
   result := Tnt_WideStringReplace(result, #10, '_', [rfReplaceAll]);

   result := Tnt_WideStringReplace(result, EXTERNAL_PATHSEPERATOR, INTERNAL_PATHSEPERATOR, [rfReplaceAll]);

   if result <> '' then begin
     EData := Form1.ExplorerNew.GetNodeData(fTreeNode);
     //// a _real_ solution for this someday would be nice :) ////////////////////////
     if (TIcon(EData.ImageIndex) in [iSoundsDir, iWaveFile, iMidiFile,              //
       iImagesDir, iImageFile, iThemeFile]) then                                    //
       begin                                                                        //
         Delete(result, 1, 1);                                                      //
         while (Length(result) > 0) and (result[1] <> INTERNAL_PATHSEPERATOR) do    //
         Delete(result, 1, 1);                                                      //
                                                                                    //
         case TIcon(EData.ImageIndex) of                                            //
           iSoundsDir,                                                              //
           iWaveFile,                                                               //
           iMidiFile: Result := INTERNAL_PATHSEPERATOR + 'snd' + result;            // do not localize
                                                                                    //
           iImagesDir,                                                              //
           iImageFile: Result := INTERNAL_PATHSEPERATOR + 'pic' + result;           // do not localize
                                                                                    //
           iThemeFile: Result := INTERNAL_PATHSEPERATOR + 'thm' + result;           // do not localize
         end;                                                                       //
       end;                                                                         //
     /////////////////////////////////////////////////////////////////////////////////
   end;
end;

procedure TFile.SetFileType(const Value: TFileType);
var EData: PFmaExplorerNode;
begin
 fFileType := Value;

 case fFileType of
  ftDir:
  begin
    EData := Form1.ExplorerNew.GetNodeData(fTreeNode);
    EData.ImageIndex := integer(iSubDir);
//   fTreeNode.StateIndex := 0;  // don't 'clean up' stateindex (yet), this might be
                                 // the root node, which needs it's abused state index to
                                 // work correctly!!
  end;

  ftFile:
  begin
    EData := Form1.ExplorerNew.GetNodeData(fTreeNode);
    EData.ImageIndex := Integer(TFiles.FindFileIcon(fExternalName));

    if Assigned(fParent) then
      case TIcon(EData.ImageIndex) of
        iMidiFile, iWaveFile:
        begin
          EData := Form1.ExplorerNew.GetNodeData(fParent.TreeNode);
          EData.ImageIndex := integer(iSoundsDir);
        end;
        iImageFile:
        begin
          EData := Form1.ExplorerNew.GetNodeData(fParent.TreeNode);
          EData.ImageIndex := integer(iImagesDir);
        end;
      end;
    end;
  end;
end;

procedure TFile.SetSize(const Value: longword);
var EData: PFmaExplorerNode;
begin
  fSize := Value;
  EData := Form1.ExplorerNew.GetNodeData(fTreeNode);
  EData.StateIndex := Value;  // state index is abused for file size
end;

procedure TFile.SetTreeNode(const Value: PVirtualNode);
var EData: PFmaExplorerNode;
begin
  fTreeNode := Value;
  fTreeView := TreeFromNode(Value);
  EData := fTreeView.GetNodeData(Value);
  EData.Data := Self;
end;

function TFile.Update: boolean;

 function CreateNewFileNode(FileName: WideString): PVirtualNode;
 // tries to locate position for new node (after dirs, alphabetically sorted)
 // if it can't find location (no files yet) places new node as last
 var CurFile: TFile;
     CurNode: PVirtualNode;
     EData: PFmaExplorerNode;
 begin
  CurNode := fTreeNode.FirstChild;

  while assigned(CurNode) do
  begin
   EData := fTreeView.GetNodeData(CurNode);
   CurFile := TFile(Edata.Data);

   if (CurFile.FileType = ftFile) and (WideCompareText(FileName, CurFile.ExternalName) < 0) then
   begin
    Result := fTreeView.InsertNode(CurNode, amInsertBefore);
    EData := fTreeView.GetNodeData(Result);
    EData.Text := FileName;
    EData.isFile := True;
    exit;
   end;

   CurNode := CurNode.NextSibling;
  end;

  Result := fTreeView.AddChild(fTreeNode);
  EData := fTreeView.GetNodeData(Result);
  EData.Text := FileName;
  EData.isFile := True;
 end;

 function CreateNewDirNode(DirName: WideString): PVirtualNode;
 // tries to locate position for new node (before files, after other dirs)
 // if it can't find location (no dirs yet) places new node as first
 var CurFile: TFile;
     CurNode: PVirtualNode;
     EData: PFmaExplorerNode;
 begin
  CurNode := fTreeNode.FirstChild;

  while assigned(CurNode) do
  begin
   EData := fTreeView.GetNodeData(CurNode);
   CurFile := TFile(EData.Data);

   if (CurFile.FileType = ftFile) then
   begin
    Result := fTreeView.InsertNode(CurFile.TreeNode, amInsertBefore);
    EData := fTreeView.GetNodeData(Result);
    EData.Text := DirName;
    EData.isFile := True;
    exit;
   end;

   CurNode := CurNode.NextSibling;
  end;

  Result := fTreeView.AddChild(fTreeNode);
  EData := fTreeView.GetNodeData(Result);
  EData.Text := DirName;
  EData.isFile := True;
 end;

 procedure AddNewFile(NewFile: TFile);
 // adds a new node in the right place in the list (kinda like CreateNewFileNode and CreateNewDirNode)
 var InsertPos: integer;
 begin
  InsertPos := fDirContents.Count - 1;

  while InsertPos >= 0 do
  begin
   with TFile(fDirContents[InsertPos]) do
    if (FileType = Newfile.FileType) and (WideCompareText(NewFile.ExternalName, ExternalName) >= 0) then
     break;

   dec(InsertPos);
  end;

  if InsertPos < 0 then
   InsertPos := 0;
  fDirContents.Insert(InsertPos, NewFile);
 end;

var
  XML: TXML;
  XMLNode: TXMLNode;
  NewFile: TFile;
  CurName: WideString;
  CurSize: WideString;
begin
 result := true;

 { Process only folders }
 if fFileType = ftFile then exit;

 if Assigned(fTreeNode) then
   fTreeView.DeleteChildren(fTreeNode);

 XML := TXML.Create;

 try
  try
   { get folder listing }
   XML.XML := Form1.ObexListFolder(FullPath, false);

   { create nodes for all files and folders }
   XMLNode := XML.FirstChild;
   while assigned(XMLNode) do
   begin
    if (SameText(XMLNode.TagName, 'file')) or // do not localize
       (SameText(XMLNode.TagName, 'folder')) then // do not localize
    begin

     NewFile := TFile.Create;
     NewFile.Parent := Self;

     CurName := LongStringToWideString(HTMLDecode(XMLNode.attribute['name'])); // do not localize
     if Form1.FUseUTF8 then CurName := UTF8StringToWideString(WideStringToLongString(CurName));

     NewFile.ExternalName := CurName;

     if SameText(XMLNode.TagName, 'file') then // do not localize
     begin
      NewFile.TreeNode := CreateNewFileNode(NewFile.ExternalName);

      CurSize := XMLNode.attribute['size']; // do not localize
      if SameText(RightStr(CurSize, 1), 'D') then                   // check for '12345d' case // do not localize
       SetLength(CurSize, Length(CurSize) - 1);                     // cut of 'd' if found

      NewFile.Size := StrToIntDef(CurSize, 0);
      NewFile.FileType := ftFile;
     end;

     if SameText(XMLNode.TagName, 'folder') then // do not localize
     begin
      NewFile.TreeNode := CreateNewDirNode(NewFile.ExternalName);
      NewFile.FileType := ftDir;
      NewFile.Update;
     end;

     AddNewFile(NewFile);
    end;

    XMLNode := XMLNode.NextSibling;
   end;

  except
   on e: Exception do
   begin
    Form1.Status(Format(_('Obex Folder Browsing not supported: %s'),[e.Message]));

    result := false;
   end;
  end;

 finally
  XML.Free;
 end;
end;

{ TFiles }

constructor TFiles.Create(AOwner: TObject; TreeNode: PVirtualNode);
begin
  fTreeNode := TreeNode;

  fRoot := TFile.Create;
  fRoot.TreeNode := fTreeNode;
  fRoot.FileType := ftDir;
end;

destructor TFiles.Destroy;
begin
  fRoot.Free;

  inherited;
end;

class function TFiles.FindFileIcon(FileName: WideString): TIcon;
var
  i: integer;
begin
  result := iUnknown;
  FileName := ExtractFileExt(FileName);

  for i := 0 to Length(FILEICONS) - 1 do
    if WideCompareText(FILEICONS[i].FileExtension,FileName) = 0 then begin
      result := FILEICONS[i].Icon;
      break;
    end;
end;

function TFiles.Update: boolean;
begin
  Form1.ObexConnect(ObexFolderBrowserServiceID);
  try
    result := fRoot.Update;
  finally
    Form1.ObexDisconnect;
  end;
end;

end.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?