disqlite3_drive_catalog_form_main.pas

来自「DELPHI 访问SQLITE3 数据库的VCL控件」· PAS 代码 · 共 2,023 行 · 第 1/5 页

PAS
2,023
字号
end;

//------------------------------------------------------------------------------

procedure TfrmMain.OpenDatabase(const AFileName: WideString);
var
  NewFocusedNode: PVirtualNode;
begin
  CloseDatabase;
  FDb.DatabaseName := AFileName;
  FDb.Open;

  BeginUpdate;
  try
    FolderTree_AddVolumes;
    NewFocusedNode := FolderTree.GetFirst;
    if Assigned(NewFocusedNode) then
      begin
        FolderTree.Selected[NewFocusedNode] := True;
        FolderTree.FocusedNode := NewFocusedNode;
      end;
  finally
    EndUpdate;
  end;
end;

//------------------------------------------------------------------------------

procedure TfrmMain.UpdateStatusBar;
var
  i: Integer;
  Tree: TVirtualStringTree;
begin
  { FolderTree. }

  i := FolderTree.SelectedCount;
  if i = 0 then
    StatusBar.Panels[0].Text := ''
  else
    StatusBar.Panels[0].Text := {$IFDEF COMPILER_9_UP}WideFormat{$ELSE}Tnt_WideFormat{$ENDIF}('%d selected', [i]);

  { FileTree or SearchResultTree. }

  if PageControl.ActivePage = tabFiles then
    Tree := FileTree
  else
    Tree := SearchResultTree;

  i := Tree.SelectedCount;
  if i = 0 then
    StatusBar.Panels[1].Text := {$IFDEF COMPILER_9_UP}WideFormat{$ELSE}Tnt_WideFormat{$ENDIF}('%d objects', [Tree.RootNodeCount])
  else
    StatusBar.Panels[1].Text := {$IFDEF COMPILER_9_UP}WideFormat{$ELSE}Tnt_WideFormat{$ENDIF}('%d objects, %d selected', [Tree.RootNodeCount, i]);
end;

//------------------------------------------------------------------------------
// All trees related.
//------------------------------------------------------------------------------

{ Implements an incremental search with no case sensitivity. }
procedure TfrmMain.Tree_IncrementalSearch(
  Sender: TBaseVirtualTree;
  Node: PVirtualNode;
  const SearchText: WideString;
  var Result: Integer);
begin
  with Sender as TVirtualStringTree do
    if Pos(WideUpperCase(SearchText), WideUpperCase(Text[Node, FocusedColumn])) <> 1 then
      Result := 1;
end;

//------------------------------------------------------------------------------

procedure TfrmMain.Tree_PaintText(
  Sender: TBaseVirtualTree;
  const TargetCanvas: TCanvas;
  Node: PVirtualNode;
  Column: TColumnIndex;
  TextType: TVSTTextType);
var
  NodeData: PNodeData;
  FileData: PFileData;
begin
  if Column = 0 then
    begin
      NodeData := Sender.GetNodeData(Node);
      FileData := FDb.GetFileData(NodeData^.ID);
      if FileData^.Attri and FILE_ATTRIBUTE_COMPRESSED <> 0 then
        TargetCanvas.Font.Color := clBlue;
    end;
end;

//------------------------------------------------------------------------------
// FolderTree related.
//------------------------------------------------------------------------------

procedure TfrmMain.FolderTree_AddVolume(const AID: Int64);
var
  Stmt, Stmt_HasSubfolders: TDISQLite3Statement;
  Node: PVirtualNode;
  NodeData: PNodeData;
begin
  BeginUpdate;
  try
    Stmt := FDb.Prepare(
      'SELECT "ID" FROM "Files" WHERE "ID"=? AND "Type"=2;');
    Stmt_HasSubfolders := FDb.Prepare(
      'SELECT "ID" FROM "Files" WHERE "Parent"=? AND "Type"=1;');
    try
      Stmt.bind_Int64(1, AID);

      if Stmt.Step = SQLITE_ROW then
        begin
          Node := FolderTree.AddChild(nil);
          NodeData := FolderTree.GetNodeData(Node);
          NodeData^.ID := Stmt.column_int64(0);

          { Check if the folder has subfolders. }
          Stmt_HasSubfolders.bind_Int64(1, NodeData^.ID);
          if Stmt_HasSubfolders.Step = SQLITE_ROW then
            FolderTree.HasChildren[Node] := True;
          Stmt_HasSubfolders.Reset;
          FolderTree.Sort(nil, 0, sdAscending, False);
        end;
    finally
      Stmt_HasSubfolders.Free;
      Stmt.Free;
    end;
  finally
    EndUpdate;
  end;
end;

//------------------------------------------------------------------------------

function TfrmMain.FolderTree_AddVolumes(const AParentNode: PVirtualNode = nil): Cardinal;
var
  Stmt, Stmt_HasSubfolders: TDISQLite3Statement;
  Node: PVirtualNode;
  NodeData: PNodeData;
begin
  BeginUpdate;
  Result := 0;
  try
    { Include both "Parent"=0 AND "Type"=2 into the WHERE clause to make it
      compatible to the index. "Parent"=0 is not actually necessary to ensure
      correct results, but it enables the index search which is drastically
      faster than without "Parent"=0. }
    Stmt := FDb.Prepare(
      'SELECT "ID" FROM "Files" WHERE "Parent"=0 AND "Type"=2 ORDER BY Name COLLATE NOCASE;');
    Stmt_HasSubfolders := FDb.Prepare(
      'SELECT "ID" FROM "Files" WHERE "Parent"=? AND "Type"=1;');
    try
      while Stmt.Step = SQLITE_ROW do
        begin
          Node := FolderTree.AddChild(AParentNode);
          NodeData := FolderTree.GetNodeData(Node);
          NodeData^.ID := Stmt.column_int64(0);

          { Check if the folder has subfolders. }
          Stmt_HasSubfolders.bind_Int64(1, NodeData^.ID);
          if Stmt_HasSubfolders.Step = SQLITE_ROW then
            FolderTree.HasChildren[Node] := True;
          Stmt_HasSubfolders.Reset;

          Inc(Result);
        end;
    finally
      Stmt_HasSubfolders.Free;
      Stmt.Free;
    end;
  finally
    EndUpdate;
  end;
end;

//------------------------------------------------------------------------------

function TfrmMain.FolderTree_AddFolders(
  const AParentNode: PVirtualNode;
  const AParentID: Int64): Cardinal;
var
  Stmt, Stmt_HasSubfolders: TDISQLite3Statement;
  Node: PVirtualNode;
  NodeData: PNodeData;
begin
  BeginUpdate;
  Result := 0;
  try
    Stmt := FDb.Prepare(
      'SELECT "ID" FROM "Files" WHERE "Parent"=? AND "Type"=1 ORDER BY Name COLLATE NOCASE;');
    Stmt_HasSubfolders := FDb.Prepare(
      'SELECT "ID" FROM "Files" WHERE "Parent"=? AND "Type"=1;');
    try
      Stmt.bind_Int64(1, AParentID);

      while Stmt.Step = SQLITE_ROW do
        begin
          Node := FolderTree.AddChild(AParentNode);
          NodeData := FolderTree.GetNodeData(Node);
          NodeData^.ID := Stmt.column_int64(0);

          { Check if the folder has subfolders. }
          Stmt_HasSubfolders.bind_Int64(1, NodeData^.ID);
          if Stmt_HasSubfolders.Step = SQLITE_ROW then
            FolderTree.HasChildren[Node] := True;
          Stmt_HasSubfolders.Reset;

          Inc(Result);
        end;
    finally
      Stmt_HasSubfolders.Free;
      Stmt.Free;
    end;
  finally
    EndUpdate;
  end;
end;

//------------------------------------------------------------------------------

procedure TfrmMain.FolderTree_Change(Sender: TBaseVirtualTree; Node: PVirtualNode);
begin
  UpdateStatusBar;
end;

//------------------------------------------------------------------------------

procedure TfrmMain.FolderTree_Collapsed(Sender: TBaseVirtualTree; Node: PVirtualNode);
begin
  if Sender.HasAsParent(Sender.FocusedNode, Node) then
    FolderTree_SelectAndFocus(Node);
end;

//------------------------------------------------------------------------------

procedure TfrmMain.FolderTree_CompareNodes(
  Sender: TBaseVirtualTree;
  Node1, Node2: PVirtualNode;
  Column: TColumnIndex;
  var Result: Integer);
var
  NodeData1, NodeData2: PNodeData;
  FileData1, FileData2: PFileData;
begin
  NodeData1 := FolderTree.GetNodeData(Node1);
  FileData1 := FDb.GetFileData(NodeData1^.ID);
  NodeData2 := FolderTree.GetNodeData(Node2);
  FileData2 := FDb.GetFileData(NodeData2^.ID);
  Result := WideCompareText(FileData1^.Name, FileData2^.Name);
end;

//------------------------------------------------------------------------------

procedure TfrmMain.FolderTree_Edited(
  Sender: TBaseVirtualTree;
  Node: PVirtualNode;
  Column: TColumnIndex);
begin
  case Column of
    0: // Name
      with FolderTree do
        begin
          Sort(NodeParent[Node], Column, sdAscending, False);
          ScrollIntoView(Node, False);
          FolderTree_Change(FolderTree, FolderTree.FocusedNode);
        end;
  end;
end;

//------------------------------------------------------------------------------

procedure TfrmMain.FolderTree_Editing(
  Sender: TBaseVirtualTree;
  Node: PVirtualNode;
  Column: TColumnIndex;
  var Allowed: Boolean);
begin
  Allowed := Column = 0;
end;

//------------------------------------------------------------------------------

procedure TfrmMain.FolderTree_FocusChanged(
  Sender: TBaseVirtualTree;
  Node: PVirtualNode;
  Column: TColumnIndex);
var
  NodeData: PNodeData;
  Volume, FullPath: WideString;
begin
  if Assigned(Node) then
    begin
      NodeData := Sender.GetNodeData(Node);
      if FDb.GetVolumeFullPath(NodeData^.ID, Volume, FullPath) then
        Caption := Volume + ' - ' + FullPath;
      FileTree_ShowFiles(NodeData^.ID);
      PageControl.ActivePage := tabFiles;
    end
  else
    begin
      Caption := APP_TITLE;
      FileTree.Clear;
    end;
  UpdateStatusBar;
end;

//------------------------------------------------------------------------------

procedure TfrmMain.FolderTree_GetImageIndexEx(
  Sender: TBaseVirtualTree;
  Node: PVirtualNode;
  Kind: TVTImageKind;
  Column: TColumnIndex;
  var Ghosted: Boolean;
  var ImageIndex: Integer;
  var ImageList: TCustomImageList);
var
  NodeData: PNodeData;
  FileData: PFileData;
begin
  case Kind of
    ikNormal, ikSelected:
      if Column = FolderTree.Header.MainColumn then
        begin
          NodeData := Sender.GetNodeData(Node);
          FileData := FDb.GetFileData(NodeData^.ID);
          if FileData^.Attri = FILE_ATTRIBUTE_VOLUME then
            begin
              ImageIndex := 0;
              ImageList := Self.ImageList;
            end
          else // If not a volume, node must be a folder
            if (Sender.FocusedNode = Node) or Sender.Expanded[Node] then
              ImageIndex := FOpenFolderIconIndex
            else
              ImageIndex := FNormalFolderIconIndex;
        end;
  end;
end;

//------------------------------------------------------------------------------

{ This is a callback for the function following below. }
procedure TfrmMain.FolderTree_CompareNodeID(
  Sender: TBaseVirtualTree;
  Node: PVirtualNode;
  Data: Pointer;
  var Abort: Boolean);
var
  NodeData: PNodeData;
begin
  NodeData := Sender.GetNodeData(Node);
  if NodeData^.ID = PInt64(Data)^ then
    Abort := True;
end;

//------------------------------------------------------------------------------

function TfrmMain.FolderTree_GetNodeFromID(const AID: Int64; const AParentNode: PVirtualNode = nil): PVirtualNode;
begin
  Result := FolderTree.IterateSubtree(AParentNode, FolderTree_CompareNodeID, @AID);
end;

//------------------------------------------------------------------------------

function TfrmMain.FolderTree_GetNodeFromPath(const AIdPath: TInt64DynArray): PVirtualNode;
var
  i: Integer;
  NodeData: PNodeData;
begin
  Result := nil;
  for i := Low(AIdPath) to High(AIdPath) do
    begin
      Result := FolderTree.GetFirstChild(Result);
      while Assigned(Result) do
        begin
          NodeData := FolderTree.GetNodeData(Result);
          if NodeData^.ID = AIdPath[i] then
            Break;
          Result := FolderTree.GetNextSibling(Result)
        end;
      if not Assigned(Result) then
        Break;
    end;
end;

//------------------------------------------------------------------------------

procedure TfrmMain.FolderTree_GetText(
  Sender: TBaseVirtualTree;
  Node: PVirtualNode;
  Column: TColumnIndex;
  TextType: TVSTTextType;
  var CellText: WideString);
var
  d: Double;
  NodeData: PNodeData;
  FileData: PFileData;
begin
  NodeData := FolderTree.GetNodeData(Node);
  FileData := FDb.GetFileData(NodeData^.ID);
  case Column of
    0: CellText := FileData^.Name;
    1: if FileData^.Size >= 0 then

⌨️ 快捷键说明

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