unit _MainFileCtl;

interface

uses
  Windows, SysUtils, Classes, Forms, INIFiles,Menus,Clipbrd,Dialogs,
  ShellAPI,Registry, _gFileInfo;

{$WARN UNIT_PLATFORM OFF}
{$WARN SYMBOL_PLATFORM OFF}

type
  TMainFileCtl = class
  private
    { Private 宣言 }
    DriveList:TStringList;
    TitleListChanged:boolean;
    procedure FileGridTitleAdd(Idx:LongInt);
    procedure OpenKDD(Filename:string);
    function  GetCurrentPath(path:string):string;
    procedure SetCurrentPath(path:string);
    procedure DriveMenuClick(Sender: TObject);
    procedure DriveMenuRegClick(Sender: TObject);
    procedure DriveMenuUnregClick(Sender: TObject);
    procedure DriveMenuEditClick(Sender: TObject);
    procedure ToClipboard(var gFileInfo:TgFileInfo;inFilename,inTitle,URL,HTML:boolean);
  public
    { Public 宣言 }
    procedure Init;
    procedure FreeMemory;
    function  GetTruePathFromVirtualPath(path:string):string;
    function  GetFullFilename(Filename:string):string;
    procedure MoveDirToUpper;
    procedure ChangeDir(Dir:string);
    procedure ChangeDrive(Drive:string);
    procedure ExecutePlayFile(Filename:string;MoveCursor:boolean);
    procedure DirectPlayFile(Filename:string);
    procedure FileGridRefresh;
    procedure FileGridTimerProcess;
    procedure MM_SetFilenameDialog(Target:string);
    procedure PlayToClipboard(inFilename,inTitle,URL,HTML:boolean);
    procedure CursorToClipboard(inFilename,inTitle,URL,HTML:boolean);
    procedure ToWavesOut(allunder,andnext:boolean);
    procedure NextPlay(vector:integer);
    procedure mdxo_Registry(reg:boolean);
    procedure mdxo_OpenReference;
  end;

var
  MainFileCtl:TMainFileCtl;

implementation

uses MainWin,KDDWin,PathHistWin,ToolTipWin,WavesOutWin,
     _m_Tools, _PicTools, _netconst,_MDXWinINI,_const, _Vis, _Images,_MDXWin_const,_Compact,
     _SndDrv_const,_SndDrv,_Vis_const, _CurrentFiles,_GridTool, _GridScroll,_GridScroll_Rap,_CSkin;

function TMainFileCtl.GetTruePathFromVirtualPath(path:string):string;
var
  Drive:string;
begin
  Result:='';
  if path='' then exit;
  Drive:=copy(path,1,1);

  if ('0'<=Drive) and (Drive<='9') then begin
    Result:=MainINI.UserPath[ord(Drive[1])-ord('0')]+copy(path,4,length(path));
  end;
  if (('a'<=Drive) and (Drive<='z')) or (('A'<=Drive) and (Drive<='Z')) or (Drive='\') then begin
    Result:=path;
  end;
  if Result='' then begin
    ShowMessage('GetTruePathFromVirtualPath('+path+')');
  end;
end;

procedure TMainFileCtl.Init;
var
  DriveNum:Integer;
  DriveBits:set of 0..25;
  DriveUpper:string;
  tmp:string;
  DriveTypeName:string;

  DriveInfo:TDriveInfo;
  DSec,DByte,DFClus,DUClus:dword;
  DFreeByte,DUseByte:Extended;

  NewItem:TMenuItem;
  cnt:integer;
  procedure ClearAndFree(var t:TMenuItem);
  var
    cnt,count:integer;
  begin
    count:=t.Count;
    for cnt:=count-1 downto 0 do begin
      t.Delete(cnt);
    end;
  end;
begin
  ClearAndFree(Main.DriveMenu_Set);
  ClearAndFree(Main.DriveMenu_All);
  ClearAndFree(Main.DriveMenu_RegUser);
  ClearAndFree(Main.DriveMenu_UnregUser);
  ClearAndFree(Main.DriveMenu_EditUser);

  DriveList:=TStringList.Create;

  DriveList.Clear;
  Integer(DriveBits):=GetLogicalDrives;
  for DriveNum:=0 to 25 do begin
    if (DriveNum in DriveBits) then begin
      if DriveNum=0 then DriveList.Add('A:\ FloppyDsk ________ no analyze');
      if DriveNum=1 then DriveList.Add('B:\ FloppyDsk ________ no analyze');
      if 2<=DriveNum then begin
        DriveUpper:=Char(DriveNum+Ord('A'))+':\';

        tmp:=DriveUpper+' ';
        DriveTypeName:=GetDriveTypeName(DriveUpper);
        tmp:=tmp+DriveTypeName;

        if DriveTypeName<>'Fixed-HDD' then begin
          tmp:=tmp+' ________ no analyze';
          end else begin
          DriveInfo:=GetDriveInfomation(DriveUpper);
          if DriveInfo.Enabled=False then begin
            tmp:=tmp+' ________ no analyze';
            end else begin
            if GetDiskFreeSpace(addr(DriveUpper[1]),DSec,DByte,DFClus,DUClus)=True then begin
              DFreeByte:=DSec;
              DFreeByte:=DFreeByte*DByte*DFClus;
              DUseByte:=DSec;
              DUseByte:=DUseByte*DByte*DUClus;
              end else begin
              DFreeByte:=0;
              DUseByte:=0;
            end;
            tmp:=tmp+' '+format('%1.8x',[DriveInfo.VolumeSerial]);
            tmp:=tmp+Format(' %16.0n/%16.0n ',[DFreeByte,DUseByte]);
            if DriveInfo.VolumeLabel<>'' then begin
              tmp:=tmp+DriveInfo.VolumeLabel;
            end;
          end;
        end;
        DriveList.Add(tmp);
      end;
    end;
  end;

  DriveList.Add('#:\ MDXOnline ________ no analyze');

  for cnt:=0 to 9 do begin
    if MainINI.UserPath[cnt]<>'' then begin
      tmp:=inttostr(cnt)+':\ UserPath  '+format('%1.8x',[GetStrCRC16(MainINI.UserPath[cnt])])+' '+MainINI.UserPath[cnt];
      DriveList.Add(tmp);
    end;
  end;

  for DriveNum:=0 to 25 do begin
    NewItem:=TMenuItem.Create(Main.DriveMenu_All);
    NewItem.Enabled:=True;
    NewItem.Caption:=Char(DriveNum+Ord('A'))+':\';
    NewItem.Tag:=ansipos(Char(DriveNum+Ord('a')),DriveName);
    NewItem.Checked:=False;
    NewItem.OnClick:=DriveMenuClick;
    Main.DriveMenu_All.Add(NewItem);
    if (DriveNum in DriveBits) then begin
      NewItem:=TMenuItem.Create(Main.DriveMenu_Set);
      NewItem.Enabled:=True;
      if DriveNum<=1 then begin
        NewItem.Caption:=Char(DriveNum+Ord('A'))+':\';
        end else begin
        DriveUpper:=Char(DriveNum+Ord('A'))+':\';
        DriveTypeName:=GetDriveTypeName(DriveUpper);
        NewItem.Caption:=DriveUpper+' '+DriveTypeName;
      end;
      NewItem.Tag:=ansipos(Char(DriveNum+Ord('a')),DriveName);
      NewItem.Checked:=False;
      NewItem.OnClick:=DriveMenuClick;
      Main.DriveMenu_Set.Add(NewItem);
    end;
  end;

  NewItem:=TMenuItem.Create(Main.DriveMenu_All);
  NewItem.Enabled:=True;
  NewItem.Caption:='#:\';
  NewItem.Tag:=ansipos('#',DriveName);
  NewItem.Checked:=False;
  NewItem.OnClick:=DriveMenuClick;
  Main.DriveMenu_All.Add(NewItem);

  NewItem:=TMenuItem.Create(Main.DriveMenu_Set);
  NewItem.Enabled:=True;
  NewItem.Caption:='#:\ MDXOnline';
  NewItem.Tag:=ansipos('#',DriveName);
  NewItem.Checked:=False;
  NewItem.OnClick:=DriveMenuClick;
  Main.DriveMenu_Set.Add(NewItem);

  for cnt:=0 to 9 do begin
    NewItem:=TMenuItem.Create(Main.DriveMenu_All);
    NewItem.Enabled:=True;
    NewItem.Caption:=inttostr(cnt)+':\';
    NewItem.Tag:=ansipos(inttostr(cnt),DriveName);
    NewItem.Checked:=False;
    NewItem.OnClick:=DriveMenuClick;
    Main.DriveMenu_All.Add(NewItem);

    if MainINI.UserPath[cnt]<>'' then begin
      NewItem:=TMenuItem.Create(Main.DriveMenu_Set);
      NewItem.Enabled:=True;
      NewItem.Caption:=inttostr(cnt)+':\ UserPath '+MainINI.UserPath[cnt];
      NewItem.Tag:=ansipos(inttostr(cnt),DriveName);
      NewItem.Checked:=False;
      NewItem.OnClick:=DriveMenuClick;
      Main.DriveMenu_Set.Add(NewItem);
    end;
  end;

  for cnt:=0 to 9 do begin
    NewItem:=TMenuItem.Create(Main.DriveMenu_RegUser);
    NewItem.Enabled:=True;
    NewItem.Caption:=inttostr(cnt)+':\ '+MainINI.UserPath[cnt];
    NewItem.Tag:=cnt;
    NewItem.Checked:=False;
    NewItem.OnClick:=DriveMenuRegClick;
    Main.DriveMenu_RegUser.Add(NewItem);
    if MainINI.UserPath[cnt]<>'' then begin
      NewItem:=TMenuItem.Create(Main.DriveMenu_UnregUser);
      NewItem.Enabled:=True;
      NewItem.Caption:=inttostr(cnt)+':\ '+MainINI.UserPath[cnt];
      NewItem.Tag:=cnt;
      NewItem.Checked:=False;
      NewItem.OnClick:=DriveMenuUnregClick;
      Main.DriveMenu_UnregUser.Add(NewItem);
    end;
    NewItem:=TMenuItem.Create(Main.DriveMenu_RegUser);
    NewItem.Enabled:=True;
    NewItem.Caption:=inttostr(cnt)+':\ '+MainINI.UserPath[cnt];
    NewItem.Tag:=cnt;
    NewItem.Checked:=False;
    NewItem.OnClick:=DriveMenuEditClick;
    Main.DriveMenu_EditUser.Add(NewItem);
  end;

end;

procedure TMainFileCtl.DriveMenuClick(Sender: TObject);
var
  DriveNum:integer;
begin
  DriveNum:=(Sender as TMenuItem).Tag;
  if DriveNum<>0 then begin
    ChangeDrive(copy(DriveName,DriveNum,1)+':\');
  end;
end;

procedure TMainFileCtl.DriveMenuRegClick(Sender: TObject);
var
  UserNum:integer;
  path,drv:string;
begin
  UserNum:=(Sender as TMenuItem).Tag;
  if (0<=UserNum) and (UserNum<=9) then begin
    path:=MainINI.CurrentFilePath;
    if path<>'' then begin
      drv:=path[1];
      if (('a'<=drv) and (drv<='z')) or (('A'<=drv) and (drv<='Z')) then begin
        MainINI.UserPath[UserNum]:=path;
        Init;
        FileGridRefresh;
        end else begin
        if (('0'<=drv) and (drv<='9')) then begin
          MainINI.UserPath[UserNum]:=GetTruePathFromVirtualPath(path);
          Init;
          FileGridRefresh;
          end else begin
          ShowMessage('ローカルドライブ(a:\〜z:\)以外は登録できません。'+CRLF+'UNC形式パス(\\ComputerName\Resource\Folder...\)を登録するときは、'+CRLF+'ユーザー定義パスの編集で直接入力してください。');
        end;
      end;
    end;
  end;
end;

procedure TMainFileCtl.DriveMenuUnregClick(Sender: TObject);
var
  UserNum:integer;
begin
  UserNum:=(Sender as TMenuItem).Tag;
  if (0<=UserNum) and (UserNum<=9) then begin
    MainINI.UserPath[UserNum]:='';
    Init;
    FileGridRefresh;
  end;
end;

procedure TMainFileCtl.DriveMenuEditClick(Sender: TObject);
var
  UserNum:integer;
  editpath:string;
begin
  UserNum:=(Sender as TMenuItem).Tag;
  if (0<=UserNum) and (UserNum<=9) then begin
    editpath:=MainINI.UserPath[UserNum];
    editpath:=InputBox('ユーザー定義パス['+inttostr(UserNum)+':\]の編集','存在確認しませんので打ち間違いに注意してくださいね。',editpath);
    if editpath<>'' then begin
      if copy(editpath,length(editpath),1)<>'\' then editpath:=editpath+'\';
    end;
    if MainINI.UserPath[UserNum]<>editpath then begin
      MainINI.UserPath[UserNum]:=editpath;
      Init;
      FileGridRefresh;
    end;
  end;
end;

procedure TMainFileCtl.FreeMemory;
begin
  DriveList.Free;
end;

function TMainFileCtl.GetCurrentPath(path:string):string;
var
  drv:string;
  cnt:integer;
begin
  // VirtualPath対応済み

  if Length(path)<=2 then begin
    Result:=path;
    exit;
  end;

  if path[2]<>':' then begin
    Result:=path;
    exit;
  end;

  drv:=lowercase(copy(path,1,1));
  cnt:=AnsiPos(drv,DriveName)-1;

  if (cnt<=-1) or (DriveMax<=cnt) then begin
    Result:=path;
    exit;
  end;

  with MainINI do begin
    if drv='#' then begin
      if CurrentPath[cnt]='' then begin
        Result:=path;
        end else begin
        Result:=CurrentPath[cnt];
      end;
      end else begin
      if CurrentPath[cnt]='' then begin
        Result:=path;
        end else begin
        if DirectoryExists(GetTruePathFromVirtualPath(CurrentPath[cnt]))=False then begin
          Result:=path;
          end else begin
          Result:=CurrentPath[cnt];
        end;
      end;
    end;
  end;

end;

procedure TMainFileCtl.SetCurrentPath(path:string);
var
  cnt:integer;
begin
  if Length(path)<=2 then exit;
  if path[2]<>':' then exit;

  cnt:=AnsiPos(lowercase(copy(path,1,1)),DriveName)-1;
  if cnt=-1 then exit;

  if path[Length(path)]<>'\' then path:=path+'\';
  MainINI.CurrentPath[cnt]:=path;
end;

procedure TMainFileCtl.MoveDirToUpper;
var
  LastDir:string;
  TempPath:string;
  Cnt,PathCnt:LongInt;
begin
  TempPath:=MainINI.CurrentFilePath;

  if length(TempPath)<=3 then exit;

  PathCnt:=0;
  if copy(TempPath,length(TempPath),1)<>'\' then TempPath:=TempPath+'\';
  cnt:=1;
  while (cnt<=(length(TempPath)-1)) do begin
    if isAnkChar(byte(TempPath[Cnt]))=False then begin
      inc(cnt,2);
      end else begin
      if TempPath[Cnt]='\' then PathCnt:=cnt;
      inc(cnt);
    end;
  end;

  if PathCnt=0 then exit;

  LastDir:=copy(TempPath,PathCnt+1,255);
  LastDir:=copy(LastDir,1,Length(LastDir)-1);
  TempPath:=copy(TempPath,1,PathCnt);

  MainINI.CurrentFilePath:=TempPath;
  SetCurrentPath(TempPath);

  FileGridRefresh;

  CurrentFiles.FindName(LastDir,True,False);
end;

procedure TMainFileCtl.ChangeDir(Dir:string);
begin
  // VirtualPath対応済み

  if Dir='' then exit;
  if Dir='..' then begin
    MoveDirToUpper;
    exit;
  end;

  if copy(Dir,2,1)=':' then begin // DirectChange
    MainINI.CurrentFilePath:=Dir;
    SetCurrentPath(Dir);
    FileGridRefresh;
    exit;
  end;

  Dir:=MainINI.CurrentFilePath+Dir+'\';
{
  if ('0'<=copy(Dir,1,1)) and (copy(Dir,1,1)<='9') then begin
    end else begin
    Dir:=thExpandFileName(Dir);
  end;
}

  if Length(Dir)>=4 then begin
    if Dir[4]='\' then begin
      ShowMessage('MDXWin.exe DebugMessage'+CRLF+dir);
      Dir:=Copy(Dir,1,3)+Copy(Dir,5,255);
    end;
  end;

  if Dir[1]<>'#' then begin
    if DirectoryExists(GetTruePathFromVirtualPath(Dir))=False then exit;
  end;

  MainINI.CurrentFilePath:=Dir;
  SetCurrentPath(Dir);
  FileGridRefresh;

  PathHist.AddPath(MainINI.CurrentFilePath);
end;

procedure TMainFileCtl.ChangeDrive(Drive:string);
begin
  // VirtualPath対応済み

  if Drive='' then exit;

  if Drive[1]<>'#' then begin
    if DirectoryExists(GetTruePathFromVirtualPath(Drive))=False then begin
      Main.InfomationVisible('Cannot preparation Logical Drive');
      exit;
    end;
  end;

  MainINI.CurrentFilePath:=GetCurrentPath(Drive);
  FileGridRefresh;

  PathHist.AddPath(MainINI.CurrentFilePath);
end;

function TMainFileCtl.GetFullFilename(Filename:string):string;
begin
  if ansipos('|',Filename)<>0 then
    Filename:=copy(Filename,1,ansipos('|',Filename)-1);

  if copy(Filename,2,2)<>':\' then begin
    if copy(Filename,1,1)='!' then delete(Filename,1,1);
    Filename:=trim(Filename);
    Filename:=MainINI.CurrentFilePath+Filename;
  end;
  Filename:=trim(Filename);
  if Length(Filename)>=4 then begin
    if Filename[4]='\' then begin
      ShowMessage('MDXWin.exe DebugMessage'+CRLF+filename);
      Filename:=Copy(Filename,1,3)+Copy(Filename,5,255);
    end;
  end;

  Result:=Filename;
end;

procedure TMainFileCtl.ExecutePlayFile(Filename:string;MoveCursor:boolean);
var
  OldFilePath,NewFilePath:string;
  ChangePath:boolean;
begin
  if Filename='' then exit;
  Filename:=GetFullFilename(Filename);
  if Filename='' then exit;

  OldFilePath:=thExtractFilePath(MainINI.CurrentFilePath);
  NewFilePath:=thExtractFilePath(Filename);

  if OldFilePath<>NewFilePath then begin
    ChangePath:=True;
    end else begin
    ChangePath:=False;
  end;

  if ChangePath=True then begin
    MainINI.CurrentFilePath:=NewFilePath;
    SetCurrentPath(NewFilePath);
    FileGridRefresh;
    PathHist.AddPath(MainINI.CurrentFilePath);
  end;

  if copy(Filename,length(Filename),1)<>'\' then begin
    DirectPlayFile(Filename);
    if (ChangePath=True) or (MoveCursor=True) then begin
      CurrentFiles.FindName(thExtractFilename(Filename),True,True);
      end else begin
      CurrentFiles.FindName(thExtractFilename(Filename),False,True);
    end;
  end;
end;

procedure TMainFileCtl.DirectPlayFile(Filename:string);
var
  msg:string;
  path,ext:string;
  PlayResult:boolean;
  ESCMode:integer;
begin
  with Main do begin
    sdStop;
    FilereadBusyFlag:=True;
    RewriteTimer.Enabled:=False;
  end;

  Filename:=GetFullFilename(Filename);

  path:=thExtractFilePath(Filename);
  Filename:=thExtractFilename(Filename);
  ext:=lowercase(ExtractFileExt(Filename));

  Main.gFileInfo.SetFileInfo(path+Filename,False);
  sdSetDriverMode(Main.gFileInfo.GetDriverMode);
  Main.ChangeDriverMode;

  if sdGetDriverMode=DriverModeUnknown then begin
    Main.InfomationVisible('no support format');
    Main.FilereadBusyFlag:=False;
    Main.RewriteTimer.Enabled:=True;
    exit;
  end;

  case sdGetDriverMode of
    DriverModeUnknown: begin end;
    DriverModeMXDRVm: begin
      sdLoadDLL_MXDRV;
      if MXDRVLoadFlag=False then begin
        ShowMessage('MXDRVが起動できませんでした。');
        Main.FilereadBusyFlag:=False;
        Main.RewriteTimer.Enabled:=True;
        exit;
      end;
    end;
    DriverModeFMP: begin
      sdLoadDLL_FMP;
      if FMPLoadFlag=False then begin
        ShowMessage('WinFMP.DLLが組み込まれていません。');
        Main.FilereadBusyFlag:=False;
        Main.RewriteTimer.Enabled:=True;
        exit;
      end;
    end;
    DriverModePMD: begin
      sdLoadDLL_PMD;
      if PMDLoadFlag=False then begin
        ShowMessage('PMDWin.DLLが組み込まれていません。');
        Main.FilereadBusyFlag:=False;
        Main.RewriteTimer.Enabled:=True;
        exit;
      end;
    end;
    DriverModeSPC: begin
      sdLoadDLL_SPC;
      if SPCLoadFlag=False then begin
        ShowMessage('SNESAPU.DLLが組み込まれていないか、バージョンが違います。');
        Main.FilereadBusyFlag:=False;
        Main.RewriteTimer.Enabled:=True;
        exit;
      end;
    end;
    DriverModeMXDRVg: begin
      sdLoadDLL_MXDRV;
      if MXDRVLoadFlag=False then begin
        ShowMessage('MXDRVが起動できませんでした。');
        Main.FilereadBusyFlag:=False;
        Main.RewriteTimer.Enabled:=True;
        exit;
      end;
    end;
    else begin end;
  end;

  if Main.gFileInfo.isNetworkMode=True then begin // MDXOnline
    PlayResult:=sdNetworkPlay;
    end else begin // LocalFile
    PlayResult:=sdPlay;
  end;

  if PlayResult=False then begin
    sdStop;
    Main.FilereadBusyFlag:=False;
    Main.RewriteTimer.Enabled:=True;
    exit;
  end;

  Main.gFileInfo.LoadTitleFromFile;

  OpenKDD(thChangeFileExt(Main.gFileInfo.GetFullPath,'.kdd'));

  with MainINI do begin
    ESCMode:=ESCModeNone;
    msg:=Main.gFileInfo.GetFullTitle;
    if TitleUseESC=True then begin
      case sdGetDriverMode of
        DriverModeMXDRVm: ESCMode:=ESCModeX68k;
        DriverModeMXDRVg: ESCMode:=ESCModeX68k;
        DriverModeFMP: begin
          ESCMode:=ESCModePC98;
          msg:=Main.gFileInfo.GetFullTitleFMPPMD;
        end;
        DriverModePMD: begin
          ESCMode:=ESCModePC98;
          msg:=Main.gFileInfo.GetFullTitleFMPPMD;
        end;
        DriverModeSPC: begin end;
        DriverModeUnknown: begin end;
        else begin end;
      end;
    end;
    msg:=strGetCompact(msg);
    if TitleUseAnk2to1byte=True then msg:=strCnvAnk2to1byte(msg);
    Main.SetMusicTitle(msg,ESCMode);
  end;

  if Main.TrayIcon<>nil then Main.TrayIcon.TipHelp:=Main.gFileInfo.GetCompactTitle;
  if IsIconic(Application.Handle)=True then begin
    ToolTip.SetText(Main.gFileInfo.GetFullPath,Main.gFileInfo.GetCompactTitle);
  end;

  Main.PlayButtonsCallback;

  Main.FilereadBusyFlag:=False;
  Main.RewriteTimer.Enabled:=True;
end;

procedure TMainFileCtl.FileGridRefresh;
// VirtualPath対応済み
var
  RootExists:boolean;
  TempList:TStrings;
  cnt:integer;
  Item:TFilesItem;
  ListAttr:string;

  PerStr:string;
  PerPos:integer;

  procedure LoadLocalFiles(path:string;var TempList:TStrings);
  var
    TruePath:string;
    res:integer;
    SearchRec:TSearchRec;
    S1Cnt,S2Cnt:integer; // Sort
    SStr:string;
    TestStr:array of String;
    MXDRVNeedFlag,FMPNeedFlag,PMDNeedFlag,SPCNeedFlag:boolean;
  begin
    TruePath:=GetTruePathFromVirtualPath(path);
    if DirectoryExists(TruePath)=False then exit;

    res:=FindFirst(TruePath+'*.*', (faDirectory or faReadOnly or faHidden or faSysFile or faArchive), SearchRec);
    if res<>0 then exit;

    RootExists:=False;
    repeat
      if (SearchRec.Attr and faDirectory)<>0 then begin
        if SearchRec.Name='..' then begin
          RootExists:=True;
          end else begin
          if (SearchRec.Name<>'.') and (SearchRec.Name<>'System Volume Information') and (SearchRec.Name<>'RECYCLER') then begin
            TempList.Add('_ < Directory >  '+SearchRec.Name);
          end;
        end;
      end;
      res:=FindNext(SearchRec);
    until (res<>0);
    FindClose(SearchRec);

    with TempList do begin
      SetLength(TestStr,Count);
      for S1Cnt:=0 to Count-1 do begin
        TestStr[S1Cnt]:=lowercase(Strings[S1Cnt]);
      end;
      for S1Cnt:=0 to Count-2 do begin
        for S2Cnt:=S1Cnt to Count-1 do begin
          if (TestStr[S1Cnt][18]<>'_') and (TestStr[S2Cnt][18]='_') then begin
            SStr:=Strings[S1Cnt];
            Strings[S1Cnt]:=Strings[S2Cnt];
            Strings[S2Cnt]:=SStr;
            SStr:=TestStr[S1Cnt];
            TestStr[S1Cnt]:=TestStr[S2Cnt];
            TestStr[S2Cnt]:=SStr;
            end else begin
            if TestStr[S1Cnt]>TestStr[S2Cnt] then begin
              SStr:=Strings[S1Cnt];
              Strings[S1Cnt]:=Strings[S2Cnt];
              Strings[S2Cnt]:=SStr;
              SStr:=TestStr[S1Cnt];
              TestStr[S1Cnt]:=TestStr[S2Cnt];
              TestStr[S2Cnt]:=SStr;
            end;
          end;
        end;
      end;
    end;

    if RootExists=True then
      TempList.Insert(0,'_ < Directory >  ..');

    Main.Catalog.FilesClear(copy(TruePath,1,length(TruePath)-1));

    if MXDRVLoadFlag=False then begin
      MXDRVNeedFlag:=False;
      if FileExists(TruePath+'*.mdx')=True then MXDRVNeedFlag:=True;
      if MXDRVNeedFlag=True then sdLoadDLL_MXDRV;
    end;

    if MXDRVLoadFlag=True then begin
      with Main.Catalog do begin
        FilesAddMask('mdx');
      end;
    end;

    if FMPLoadFlag=False then begin
      FMPNeedFlag:=False;
      if FileExists(TruePath+'*.opi')=True then FMPNeedFlag:=True;
      if FileExists(TruePath+'*.ovi')=True then FMPNeedFlag:=True;
      if FileExists(TruePath+'*.ozi')=True then FMPNeedFlag:=True;
      if FMPNeedFlag=True then sdLoadDLL_FMP;
    end;

    if FMPLoadFlag=True then begin
      with Main.Catalog do begin
        if FMPLoadFlag=True then begin
          FilesAddMask('opi');
          FilesAddMask('ovi');
          FilesAddMask('ozi');
        end;
      end;
    end;

    if PMDLoadFlag=False then begin
      PMDNeedFlag:=False;
      if FileExists(TruePath+'*.m')=True then PMDNeedFlag:=True;
      if FileExists(TruePath+'*.m2')=True then PMDNeedFlag:=True;
      if FileExists(TruePath+'*.mz')=True then PMDNeedFlag:=True;
      if PMDNeedFlag=True then sdLoadDLL_PMD;
    end;

    if PMDLoadFlag=True then begin
      with Main.Catalog do begin
        if PMDLoadFlag=True then begin
          FilesAddMask('m');
          FilesAddMask('m2');
          FilesAddMask('mz');
        end;
      end;
    end;

    if SPCLoadFlag=False then begin
      SPCNeedFlag:=False;
      if FileExists(TruePath+'*.spc')=True then SPCNeedFlag:=True;
      if FileExists(TruePath+'*.sp0')=True then SPCNeedFlag:=True;
      if FileExists(TruePath+'*.sp1')=True then SPCNeedFlag:=True;
      if FileExists(TruePath+'*.sp2')=True then SPCNeedFlag:=True;
      if FileExists(TruePath+'*.sp3')=True then SPCNeedFlag:=True;
      if FileExists(TruePath+'*.sp4')=True then SPCNeedFlag:=True;
      if FileExists(TruePath+'*.sp5')=True then SPCNeedFlag:=True;
      if FileExists(TruePath+'*.sp6')=True then SPCNeedFlag:=True;
      if FileExists(TruePath+'*.sp7')=True then SPCNeedFlag:=True;
      if FileExists(TruePath+'*.sp8')=True then SPCNeedFlag:=True;
      if FileExists(TruePath+'*.sp9')=True then SPCNeedFlag:=True;
      if SPCNeedFlag=True then sdLoadDLL_SPC;
    end;

    if SPCLoadFlag=True then begin
      with Main.Catalog do begin
        if SPCLoadFlag=True then begin
          FilesAddMask('spc');
          FilesAddMask('sp0');
          FilesAddMask('sp1');
          FilesAddMask('sp2');
          FilesAddMask('sp3');
          FilesAddMask('sp4');
          FilesAddMask('sp5');
          FilesAddMask('sp6');
          FilesAddMask('sp7');
          FilesAddMask('sp8');
          FilesAddMask('sp9');
        end;
      end;
    end;

    Main.Catalog.FilesLoadList;
    if Main.Catalog.GetFileCount<>0 then begin
      TitleListChanged:=Main.Catalog.LoadData(copy(path,1,length(path)-1),TempList);
      TempList.Add(TempList[0]);
    end;
  end;
begin
  TempList:=TStringList.Create;
  TempList.Clear;

  with MainINI do begin
    if CurrentFilePath[1]='#' then begin
      Main.Network.LoadFiles(copy(CurrentFilePath,1,length(CurrentFilePath)-1),TempList,True);
      TitleListChanged:=False;
      end else begin
      LoadLocalFiles(CurrentFilePath,TempList);
    end;
  end;

  // Get Logical Drives
  for cnt:=0 to DriveList.Count-1 do begin
    TempList.Add(DriveList[cnt]);
  end;

  CurrentFiles.SetItemsCount(TempList.Count);
  for cnt:=0 to TempList.Count-1 do begin
    Item.Attr:=ir_None;
    ListAttr:=copy(TempList[cnt],1,1);
    if AnsiPos(lowercase(ListAttr),DriveName)<>0 then begin
      Item.Attr:=ir_Drive;
      Item.Name:=copy(TempList[cnt],1,3);
      Item.Value:=copy(TempList[cnt],5,255);
    end;
    if ListAttr='_' then begin
      Item.Attr:=ir_Dir;
      Item.Name:=copy(TempList[cnt],18,255);
      Item.Value:='';
    end;
    if (ListAttr=' ') or (ListAttr='!') then begin
      Item.Attr:=ir_File;
      PerStr:=copy(TempList[cnt],3,255);
      PerPos:=AnsiPos('|',PerStr);
      if PerPos=0 then begin
        Item.Name:=PerStr;
        Item.Value:='';
        end else begin
        Item.Name:=copy(PerStr,1,PerPos-1);
        Item.Value:=copy(PerStr,PerPos+1,255);
      end;
    end;
    CurrentFiles.SetItem(cnt,Item);
  end;
  CurrentFiles.SetCursorIndex(0);
  TempList.Free;

  Main.FileGridTimer.Interval:=16;
  Main.FileGridTimer.Enabled:=True;

  GS_Main.ResetPosition;
end;

procedure TMainFileCtl.FileGridTimerProcess;
var
  NowIdx,Idx:LongInt;
  cnt:integer;
  TempList:TStrings;
  Item:TFilesItem;
begin
  with Main do begin
    if FilereadBusyFlag=True then exit;
    FileGridTimer.Interval:=50;
    if CurrentFiles.GetItemsCount<=0 then begin
      FileGridTimer.Enabled:=False;
      exit;
    end;
  end;

  NowIdx:=Grid_GetIndex(Main.FileGrid)-7;
  if NowIdx<0 then NowIdx:=0;

  cnt:=2;
  for Idx:=NowIdx to CurrentFiles.GetItemsCount-1 do begin
    CurrentFiles.GetItem(Idx,Item);
    if Item.Attr=ir_File then begin
      if Item.Value='' then begin
        FileGridTitleAdd(Idx);
        dec(cnt);
        if cnt=0 then exit;
      end;
    end;
  end;

  for Idx:=0 to NowIdx do begin
    CurrentFiles.GetItem(Idx,Item);
    if Item.Attr=ir_File then begin
      if Item.Value='' then begin
        FileGridTitleAdd(Idx);
        dec(cnt);
        if cnt=0 then exit;
      end;
    end;
  end;

  if TitleListChanged=True then begin
    TempList:=TStringList.Create;
    TempList.Clear;
    TempList.Capacity:=CurrentFiles.GetItemsCount;
    for cnt:=0 to CurrentFiles.GetItemsCount-1 do begin
      if CurrentFiles.GetItemAttr(cnt)=ir_File then begin
        CurrentFiles.GetItem(cnt,Item);
        TempList.Add(' '+Item.Name+'|'+Item.Value);
      end;
    end;
    with MainINI do begin
      Main.Catalog.SaveData(copy(CurrentFilePath,1,length(CurrentFilePath)-1),TempList);
    end;
    TempList.Free;
    TitleListChanged:=False;
  end;

  Main.FileGridTimer.Enabled:=False;
end;

procedure TMainFileCtl.FileGridTitleAdd(Idx:LongInt);
var
  Item:TFilesItem;
  Filename,FullPath:string;
  ext:string;
  Title:string;
  gFileInfo:TgFileInfo;
begin
  // VirtualPath対応済み

  CurrentFiles.GetItem(Idx,Item);
  Filename:=Item.Name;
  FullPath:=MainINI.CurrentFilePath+Filename;
  ext:=lowercase(ExtractFileExt(FullPath));

  Title:='';

  gFileInfo:=TgFileInfo.Create;
  gFileInfo.SetFileInfo(FullPath,False);
  gFileInfo.LoadTitleFromFile;
  Title:=gFileInfo.GetCompactTitle;
  gFileInfo.Free;
  if Title='' then Title:='['+Filename+']';

  Item.Value:=Title;
  CurrentFiles.SetItem(Idx,Item);

  TitleListChanged:=True;
end;

procedure TMainFileCtl.OpenKDD(Filename:string);
begin
  if MainINI.UseKDD=False then begin
    if Main.KDDLoaded=True then begin
      KDD.FreeKDDNowFile;
      KDD.Visible:=False;
    end;
    exit;
  end;

  if (FileExists(Filename)=False) or ((sdGetDriverMode<>DriverModeMXDRVm) and (sdGetDriverMode<>DriverModeMXDRVg)) then begin
    if Main.KDDLoaded=True then begin
      KDD.FreeKDDNowFile;
      KDD.Visible:=False;
    end;
    exit;
  end;

  if Main.KDDLoaded=False then begin
    Main.KDDLoaded:=True;
    Application.CreateForm(TKDD, KDD);
  end;

  KDD.RefrectSetting;
  if KDD.LoadKDDFile(Filename)=True then begin
    KDD.Start;
  end;
end;

procedure TMainFileCtl.MM_SetFilenameDialog(Target:string);
var
  Dir:string;
  Drv:string;
  p:integer;
  ext:string;
  function GetLastPos(p:char;src:string):integer;
  var
    cnt:integer;
  begin
    Result:=0;
    if src='' then exit;
    cnt:=1;
    while (cnt<=length(src)) do begin
      if isAnkChar(byte(src[cnt]))=True then begin
        if src[cnt]=p then begin
          Result:=cnt;
        end;
        inc(cnt);
        end else begin
        inc(cnt,2);
      end;
    end;
  end;
begin
  if Target<>'' then begin
    Dir:=Target;
    end else begin
    Dir:=Main.gFileInfo.GetFullPath;
  end;

  if InputQuery('ファイル名を指定して再生/移動','存在しないフォルダを指定しても落ちないはずですが一応注意してください。',Dir)=False then begin
    Dir:='';
  end;

  if Dir<>'' then begin
    p:=AnsiPos(':///',Dir);
    if p<>0 then begin
      Dir:='#:\'+copy(Dir,p+4,255);
      if ansipos('"',Dir)<>0 then Dir:=copy(Dir,1,ansipos('"',Dir)-1);
      Dir:=ConvURL2Filename(Dir);
      p:=ansipos('.',Dir);
      if p=0 then exit;
      ext:=copy(Dir,p,4);
      Dir:=copy(Dir,1,p-1);
      if ansipos(' ',ext)<>0 then ext:=copy(ext,1,ansipos(' ',ext)-1);
      if ansipos('"',ext)<>0 then ext:=copy(ext,1,ansipos('"',ext)-1);
      ExecutePlayFile(Dir+ext,True);
      exit;
    end;
  end;

  if Dir<>'' then begin
    p:=AnsiPos(':\',Dir);
    if p=0 then begin
      ShowMessage('ドライブ部分が見つかりませんでした。');
      exit;
    end;
    if p=1 then begin
      Dir:='#'+Dir; // :\が先頭だったら#を挿入。
      end else begin
      Dir:=copy(Dir,p-1,255); // 先頭でなかったら:\より一つ前の文字から切り出し
      Drv:=copy(Dir,1,1);
      if ((Drv<'a') or ('z'<Drv)) and ((Drv<'A') or ('Z'<Drv)) and ((Drv<'0') or ('9'<Drv)) and (Drv<>'#') then begin
        Dir[1]:='#'; // 認識できないドライブだった時はMDXOnlineと仮定する。
      end;
    end;
    if AnsiPos('/',Dir)<>0 then begin
      Dir:=copy(Dir,1,ansipos('/',Dir)-1); // スラッシュ以降は削除
    end;
    Dir:=Trim(Dir); // 文頭文末の空白を削除
    if Length(Dir)=0 then exit; // 空っぽになることはないはずだけど一応
    if GetLastPos('.',Dir)<GetLastPos('\',Dir) then begin
      if Dir[Length(Dir)]<>'\' then Dir:=Dir+'\'; // パス指定で文末が\でないときは追加
      end else begin
      // ファイルだった時はドット以降３文字を残して削除
      Dir:=copy(Dir,1,GetLastPos('.',Dir)+3);
      Dir:=Trim(Dir);
    end;
    ExecutePlayFile(Dir,True);
  end;
end;

procedure TMainFileCtl.ToClipboard(var gFileInfo:TgFileInfo;inFilename,inTitle,URL,HTML:boolean);
var
  sFilename:string;
  sTitle:string;
  msg:string;
begin
  if gFileInfo.GetFullPath='' then begin
    ShowMessage('ファイル情報が取得できませんでした。');
    exit;
  end;

  gFileInfo.LoadTitleFromCatalog;
  sFilename:=gFileInfo.GetFullPath;
  sTitle:=gFileInfo.GetCompactTitle;

  if URL=True then begin
    if copy(sFilename,1,3)<>'#:\' then begin
      ShowMessage('MDXOnline内のファイル以外はリンクできません。');
      exit;
    end;
    sFilename:=ConvPath2URL('mdxo:///',sFilename);
  end;

  msg:='';

  if (inFilename=True) and (inTitle=True) then begin
    msg:=sFilename+' / '+sTitle;
  end;
  if (inFilename=True) and (inTitle=False) then begin
    msg:=sFilename;
  end;
  if (inFilename=False) and (inTitle=True) then begin
    msg:=sTitle;
  end;

  if HTML=True then begin
    msg:='<A HREF="'+sFilename+'">';
    if (inFilename=True) and (inTitle=True) then begin
      msg:=msg+sFilename+' / '+sTitle;
    end;
    if (inFilename=True) and (inTitle=False) then begin
      msg:=msg+sFilename;
    end;
    if (inFilename=False) and (inTitle=True) then begin
      msg:=msg+sTitle;
    end;
    msg:=msg+'</A>';
  end;

  Clipboard.AsText:=msg;
end;

procedure TMainFileCtl.PlayToClipboard(inFilename,inTitle,URL,HTML:boolean);
begin
  ToClipboard(Main.gFileInfo,inFilename,inTitle,URL,HTML);
end;

procedure TMainFileCtl.CursorToClipboard(inFilename,inTitle,URL,HTML:boolean);
var
  gFileInfo:TgFileInfo;
  SelectItem:TFilesItem;
begin
  if CurrentFiles.GetCursorIndex<0 then exit;
  CurrentFiles.GetItem(CurrentFiles.GetCursorIndex,SelectItem);

  case SelectItem.Attr of
    ir_None:  ShowMessage('未定義エラー');
    ir_Drive: ShowMessage('ドライブ上では実行できません。');
    ir_Dir:   ShowMessage('フォルダ上では実行できません。');
    ir_File:  begin
      gFileInfo:=TgFileInfo.Create;
      gFileInfo.SetFileInfo(GetFullFilename(SelectItem.Name),False);
      ToClipboard(gFileInfo,inFilename,inTitle,URL,HTML);
      gFileInfo.Free;
    end;
  end;
end;

procedure TMainFileCtl.ToWavesOut(allunder,andnext:boolean);
var
  LoopFlag:boolean;
begin
  if Main.WavesFormLoaded=False then begin
    ShowMessage('Shift+Returnでカーソル位置のファイルを登録'+CRLF+'Shift+Spaceでカーソル位置のファイルを登録し次の行に移動'+CRLF+'Ctrl+Spaceでカーソル位置以下全てのファイルを登録'+CRLF+'右クリックメニューからの登録'+CRLF+CRLF+'以上の機能はWave/MP3/Ogg変換ウィンドウが開いているときのみ有効です。');
    exit;
  end;

  if allunder=False then begin
    Main.CreateDragFilesOne(CurrentFiles.GetCursorIndex);
    if Main.DragFiles.Enabled=True then begin
      WavesOut.encGridDragDrop(nil,nil,0,0);
      Main.DragFiles.Enabled:=False;
      if andnext=True then CurrentFiles.SetCursorIndex(CurrentFiles.GetCursorIndex+1);
    end;
    end else begin
    LoopFlag:=True;
    while (LoopFlag=True) do begin
      Main.CreateDragFilesOne(CurrentFiles.GetCursorIndex);
      if Main.DragFiles.Enabled=True then begin
        WavesOut.encGridDragDrop(nil,nil,0,0);
        Main.DragFiles.Enabled:=False;
        CurrentFiles.SetCursorIndex(CurrentFiles.GetCursorIndex+1);
        end else begin
        LoopFlag:=False;
      end;
    end;
  end;
end;

procedure TMainFileCtl.NextPlay(vector:integer);
var
  ItemsCount,PlayIdx,ReqIdx:integer;
  function GetNextSingle:integer;
  begin
    Result:=PlayIdx;
  end;
  function GetNextALL:integer;
  begin
    Result:=PlayIdx+1;
  end;
  function GetNextALLRepeat:integer;
  var
    idx,cnt:integer;
  begin
    idx:=PlayIdx+1;
    if CurrentFiles.GetItemAttr(idx)<>ir_File then begin
      idx:=-1;
      for cnt:=0 to ItemsCount-1 do begin
        if CurrentFiles.GetItemAttr(cnt)=ir_File then begin
          idx:=cnt;
          break;
        end;
      end;
    end;
    Result:=idx;
  end;
  function GetNextRandom:integer;
  var
    RandomCount:integer;
    RandomList:array of integer;
    cnt:integer;
  begin
    RandomCount:=0;
    SetLength(RandomList,RandomCount);
    for cnt:=0 to ItemsCount-1 do begin
      if CurrentFiles.GetItemAttr(cnt)=ir_File then begin
        SetLength(RandomList,RandomCount+1);
        RandomList[RandomCount]:=cnt;
        inc(RandomCount);
      end;
    end;
    if RandomCount=-1 then begin
      Result:=-1;
      exit;
    end;
    Result:=RandomList[integer(GetTickCount) mod RandomCount];
  end;
  function GetNextNone:integer;
  begin
    Result:=-1;
  end;
begin
  if Application.Title='MDXClose' then exit;

  if sdReqFadeStop=True then begin
    sdStop;
    exit;
  end;
  sdStop;

  ItemsCount:=CurrentFiles.GetItemsCount;
  PlayIdx:=CurrentFiles.GetPlayIndex;

  if PlayIdx=-1 then exit;

  case vector of
    -1: ReqIdx:=PlayIdx-1;
    1:  ReqIdx:=PlayIdx+1;
    0: begin
      case MainINI.PlayMode of
        PlayMode_Single:    ReqIdx:=GetNextSingle;
        PlayMode_ALL:       ReqIdx:=GetNextALL;
        PlayMode_ALLRepeat: ReqIdx:=GetNextALLRepeat;
        PlayMode_Random:    ReqIdx:=GetNextRandom;
        PlayMode_None:      ReqIdx:=GetNextNone;
        else ReqIdx:=-1;
      end;
    end;
    else ReqIdx:=-1;
  end;

  if ReqIdx=-1 then exit;

  if CurrentFiles.GetItemAttr(ReqIdx)=ir_File then ExecutePlayFile(CurrentFiles.GetItemName(ReqIdx),False);
end;

procedure TMainFileCtl.mdxo_Registry(reg:boolean);
var
  RootKey:HKEY;
  procedure RegistryReg;
  var
    reg:TRegistry;
    path:string;
  begin
    Reg:=TRegistry.Create;
    Reg.RootKey:=RootKey;
    path:='\mdxo';
    if Reg.OpenKey(path, True)=True then begin
      Reg.WriteString('','URL:MDXOnlineDynLink Protocol (mdxo)');
      Reg.WriteString('URL Protocol','');
      Reg.CloseKey;
    end;
    Reg.Free;

    Reg:=TRegistry.Create;
    Reg.RootKey:=RootKey;
    path:='\mdxo\shell\open\command';
    if Reg.OpenKey(path, True)=True then begin
      Reg.WriteString('','"'+Application.ExeName+'" "%1"');
      Reg.CloseKey;
    end;
    Reg.Free;
  end;
  procedure RegistryUnreg;
  var
    reg:TRegistry;
    path:string;
  begin
    Reg:=TRegistry.Create;
    Reg.RootKey:=RootKey;
    path:='\mdxo';
    Reg.DeleteKey(path);
    Reg.Free;

    Reg:=TRegistry.Create;
    Reg.RootKey:=RootKey;
    path:='\mdxo\shell\open\command';
    Reg.DeleteKey(path);
    Reg.Free;
  end;
begin
  RootKey:=HKEY_CLASSES_ROOT;
  if Reg=True then
    RegistryReg
    else
    RegistryUnreg;

  RootKey:=HKEY_LOCAL_MACHINE;
  if Reg=True then
    RegistryReg
    else
    RegistryUnreg;

  if Reg=True then begin
    ShowMessage('URL:MDXOnlineDynLink Protocol (mdxo)'+CRLF+'をインストールしました。');
    end else begin
    ShowMessage('URL:MDXOnlineDynLink Protocol (mdxo)'+CRLF+'をアンインストールしました。');
  end;
end;

procedure TMainFileCtl.mdxo_OpenReference;
var
  Filename:string;
begin
  Filename:='http://home.att.ne.jp/blue/moonlight/mdxo_ref.html';
  ShellExecute(0,'',PChar(Filename),nil, nil,SW_SHOW);
end;

end.
