disqlite3_drive_catalog_form_main.pas

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

PAS
2,023
字号
      end;
    VK_RETURN:
      FileTree_NodeAction(FileTree.FocusedNode);
  end;
end;

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

procedure TfrmMain.FileTree_NewText(
  Sender: TBaseVirtualTree;
  Node: PVirtualNode;
  Column: TColumnIndex;
  NewText: WideString);
var
  NodeData: PNodeData;
begin
  case Column of
    0:
      begin
        NodeData := FileTree.GetNodeData(Node);
        FDb.UpdateName(NodeData^.ID, NewText);
      end;
  end;
end;

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

procedure TfrmMain.FileTree_NodeAction(const ANode: PVirtualNode);
var
  NodeData: PNodeData;
  FileData: PFileData;
begin
  if Assigned(ANode) then
    begin
      NodeData := FileTree.GetNodeData(ANode);
      FileData := FDb.GetFileData(NodeData^.ID);
      if FileData^.Attri and FILE_ATTRIBUTE_DIRECTORY <> 0 then
        FolderTree_FocusID(NodeData^.ID);
    end;
end;

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

procedure TfrmMain.FileTree_Purge;
var
  Node, NextNode, NewFocusedNode: PVirtualNode;
  NodeData: PNodeData;
  Stmt: TDISQLite3Statement;
begin
  FileTree.BeginUpdate;
  try
    Node := FileTree.GetFirst;
    if Assigned(Node) then
      begin
        Stmt := FDb.Prepare('SELECT "ID" FROM "Files" WHERE "ID"=?;');
        try
          NewFocusedNode := FileTree.FocusedNode;
          repeat
            NodeData := FileTree.GetNodeData(Node);
            Stmt.bind_Int64(1, NodeData^.ID);
            if not Stmt.Step = SQLITE_ROW then
              begin
                { If node is not in the DB anymore, find a new focused node
                  and delete the node. }
                if NewFocusedNode = Node then
                  begin
                    NewFocusedNode := FileTree.GetNextSibling(Node);
                    if not Assigned(NewFocusedNode) then
                      NewFocusedNode := FileTree.GetPreviousSibling(Node);
                  end;
                NextNode := FileTree.GetNextSibling(Node);
                FileTree.DeleteNode(Node);
                Node := NextNode;
              end
            else
              Node := FileTree.GetNextSibling(Node);
            Stmt.Reset;
          until not Assigned(Node);

          if NewFocusedNode <> FileTree.FocusedNode then
            begin
              FileTree.ClearSelection;
              FileTree.Selected[NewFocusedNode] := True;
              FileTree.FocusedNode := NewFocusedNode;
            end;
        finally
          Stmt.Free;
        end;
      end;
  finally
    FileTree.EndUpdate;
  end;
end;

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

procedure TfrmMain.FileTree_RemoveSelected;
var
  Node, NewFocusedNode: PVirtualNode;
  NodeData: PNodeData;
begin
  BeginUpdate;
  try
    Node := FileTree.GetFirstSelected;
    if Assigned(Node) then
      begin
        FDb.StartTransaction;
        try
          { Delete selected nodes from DB. }
          NewFocusedNode := FileTree.FocusedNode;
          repeat
            NodeData := FileTree.GetNodeData(Node);
            FDb.Delete(NodeData^.ID);
            if NewFocusedNode = Node then
              begin
                NewFocusedNode := FileTree.GetNextSibling(Node);
                if not Assigned(NewFocusedNode) then
                  NewFocusedNode := FileTree.GetPreviousSibling(Node);
              end;
            Node := FileTree.GetNextSelected(Node);
          until not Assigned(Node);
          FDb.Commit;

          { Delete selected nodes from tree, set new focus and selection. }
          FileTree.DeleteSelectedNodes;
          if NewFocusedNode <> FileTree.FocusedNode then
            begin
              FileTree.Selected[NewFocusedNode] := True;
              FileTree.FocusedNode := NewFocusedNode;
            end;
          FolderTree_UpdateNodePath(FolderTree.FocusedNode);
          SearchResultTree_Purge;

          FDb.Invalidate;
        except
          FDb.Rollback;
          raise;
        end;
      end;
  finally
    EndUpdate;
  end;
end;

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

function TfrmMain.FileTree_ShowFiles(const AParentID: Int64): Cardinal;
var
  Node: PVirtualNode;
  NodeData: PNodeData;
  Stmt: TDISQLite3Statement;
  SQL: AnsiString;
begin
  Result := 0;
  FileTree.BeginUpdate;
  try
    FFileTreeParentID := AParentID;
    FileTree.Clear;

    { Construct the SQL statement according to the current sorting. }
    // SQL := 'SELECT "ID" FROM "Files" WHERE "Parent"=? AND "Type" IN (0,1) ORDER BY ';
    SQL := 'SELECT "ID" FROM "Files" WHERE "Parent"=? AND ("Type"=0 OR "Type"=1) ORDER BY ';
    case FileTree.Header.SortColumn of
      1:
        if FileTree.Header.SortDirection = sdAscending then
          SQL := SQL + '"Size";'
        else
          SQL := SQL + '"Size" DESC;';
      2:
        if FileTree.Header.SortDirection = sdAscending then
          SQL := SQL + '"Time";'
        else
          SQL := SQL + '"Time" DESC;';
      3:
        if FileTree.Header.SortDirection = sdAscending then
          SQL := SQL + '"Attr";'
        else
          SQL := SQL + '"Attr" DESC;'
      else
        if FileTree.Header.SortDirection = sdAscending then
          SQL := SQL + '"Type" DESC, "Name" COLLATE NOCASE;'
        else
          SQL := SQL + '"Type", "Name" COLLATE NOCASE DESC;'
    end;

    Stmt := FDb.Prepare(SQL);
    try
      Stmt.bind_Int64(1, AParentID);

      while Stmt.Step = SQLITE_ROW do
        begin
          Node := FileTree.AddChild(nil);
          NodeData := FileTree.GetNodeData(Node);
          NodeData^.ID := Stmt.column_int64(0);
          Inc(Result);
        end;
    finally
      Stmt.Free;
    end;

    FileTree.FocusedNode := FileTree.GetFirst;
  finally
    FileTree.EndUpdate;
  end;
end;

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

procedure TfrmMain.FileTree_Sort;
var
  Node: PVirtualNode;
  NodeData: PNodeData;
  NodeID: Int64;
begin
  { For a great many files, reloading the tree is actually faster than
    sorting it in memory. This is because the sorting routine will
    eventually touch all files and cause their full details to be loaded. }
  if FileTree.VisibleCount > 512 then
    begin
      Node := FileTree.FocusedNode;
      if Assigned(Node) then
        begin
          NodeData := FileTree.GetNodeData(Node);
          NodeID := NodeData^.ID;
        end
      else
        NodeID := -1;
      FileTree_ShowFiles(FFileTreeParentID);
      if NodeID >= 0 then
        FileTree_FocusID(NodeID);
    end
  else
    with FileTree, Header do
      begin
        Sort(nil, SortColumn, SortDirection);
        ScrollIntoView(FocusedNode, False);
      end;
end;

//------------------------------------------------------------------------------
// SearchResultTree
//------------------------------------------------------------------------------

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

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

procedure TfrmMain.SearchResultTree_CompareNodes(
  Sender: TBaseVirtualTree;
  Node1, Node2: PVirtualNode;
  Column: TColumnIndex;
  var Result: Integer);
var
  NodeData1, NodeData2: PNodeData;
  FileData1, FileData2: PFileData;
  v, p, vp1, vp2: WideString;
begin
  NodeData1 := FileTree.GetNodeData(Node1);
  FileData1 := FDb.GetFileData(NodeData1^.ID);
  NodeData2 := FileTree.GetNodeData(Node2);
  FileData2 := FDb.GetFileData(NodeData2^.ID);
  case Column of
    0: // Name
      begin
        Result := (FileData2^.Attri and FILE_ATTRIBUTE_DIRECTORY) - (FileData1^.Attri and FILE_ATTRIBUTE_DIRECTORY);
        if Result = 0 then
          Result := WideCompareText(FileData1^.Name, FileData2^.Name);
      end;
    1:
      begin
        FDb.GetVolumeFullPath(FileData1^.Parent, v, p);
        vp1 := v + p;
        FDb.GetVolumeFullPath(FileData2^.Parent, v, p);
        vp2 := v + p;
        Result := WideCompareText(vp1, vp2);
      end;
    2: // Size:
      if FileData1^.Size > FileData2^.Size then
        Result := 1
      else
        if FileData1^.Size < FileData2^.Size then
          Result := -1
        else
          Result := 0;
    3: // Time
      if FileData1^.Time > FileData2^.Time then
        Result := 1
      else
        if FileData1^.Time < FileData2^.Time then
          Result := -1
        else
          Result := 0;
    4: // Attributes
      if FileData1^.Attri > FileData2^.Attri then
        Result := 1
      else
        if FileData1^.Attri < FileData2^.Attri then
          Result := -1
        else
          Result := 0;
  end;
end;

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

procedure TfrmMain.SearchResultTree_DblClick(Sender: TObject);
var
  CP: TPoint;
  HitInfo: THitInfo;
begin
  if GetCursorPos(CP) then
    begin
      CP := SearchResultTree.ScreenToClient(CP);
      SearchResultTree.GetHitTestInfoAt(CP.x, CP.y, True, HitInfo);
      SearchResultTree_NodeAction(HitInfo.HitNode);
    end;
end;

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

procedure TfrmMain.SearchResultTree_GetImageIndex(
  Sender: TBaseVirtualTree;
  Node: PVirtualNode;
  Kind: TVTImageKind;
  Column: TColumnIndex;
  var Ghosted: Boolean;
  var ImageIndex: Integer);
var
  NodeData: PNodeData;
  FileData: PFileData;
begin
  case Kind of
    ikNormal, ikSelected:
      if Column = SearchResultTree.Header.MainColumn then
        begin
          NodeData := SearchResultTree.GetNodeData(Node);
          FileData := FDb.GetFileData(NodeData^.ID);
          if FileData^.Attri and FILE_ATTRIBUTE_DIRECTORY <> 0 then
            ImageIndex := FNormalFolderIconIndex
          else
            ImageIndex := FileData^.IconIdx;
          if FileData^.Attri and FILE_ATTRIBUTE_HIDDEN <> 0 then
            Ghosted := True;
        end;
  end;
end;

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

procedure TfrmMain.SearchResultTree_GetText(
  Sender: TBaseVirtualTree;
  Node: PVirtualNode;
  Column: TColumnIndex;
  TextType: TVSTTextType;
  var CellText: WideString);
var
  NodeData: PNodeData;
  FileData: PFileData;
  Volume, FullPath: WideString;
  d: Double;
begin
  NodeData := SearchResultTree.GetNodeData(Node);
  FileData := FDb.GetFileData(NodeData^.ID);
  case Column of
    0: // Name
      begin
        CellText := FileData^.Name;
      end;
    1: // Path
      begin
        if FDb.GetVolumeFullPath(FileData^.Parent, Volume, FullPath) then
          CellText := Volume + ' - ' + FullPath; ;
      end;
    2: // Size
      if FileData^.Size >= 0 then
        begin
          d := (FileData^.Size + 1023) div 1024;
          CellText := {$IFDEF COMPILER_9_UP}WideFormat{$ELSE}Tnt_WideFormat{$ENDIF}('%.0n KB', [d]);
        end;
    3: // Time
      begin
        CellText := JulianDateToDateTimeString(FileData^.Time);
      end;
    4: // Attributes
      begin
        CellText := FileAttributesToString(FileData^.Attri);
      end;
  end;
end;

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

procedure TfrmMain.SearchResultTree_HeaderClick(
  Sender: TVTHeader;
  Column: TColumnIndex;
  Button: TMouseButton;
  Shift: TShiftState;
  x, y: Integer);
begin
  if Button = mbLeft then
    with SearchResultTree, Header do
      begin

⌨️ 快捷键说明

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