mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-28 10:02:14 +00:00
938 lines
28 KiB
ObjectPascal
938 lines
28 KiB
ObjectPascal
{
|
|
Double Commander
|
|
-------------------------------------------------------------------
|
|
File Properties Dialog
|
|
|
|
Copyright (C) 2003-2004 Radek Cervinka (radek.cervinka@centrum.cz)
|
|
Copyright (C) 2003 Martin Matusu <xmat@volny.cz>
|
|
Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru)
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
}
|
|
|
|
unit fFileProperties;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
LResources, SysUtils, Classes, Graphics, Forms, StdCtrls, Buttons, ComCtrls,
|
|
Dialogs, Controls, ExtCtrls, Grids, ButtonPanel, DividerBevel, KASCDEdit,
|
|
DCBasicTypes, uFile, uFileProperty, uFileSource, uFileSourceOperation,
|
|
uFileSourceCalcStatisticsOperation, uFileSourceSetFilePropertyOperation,
|
|
DCOSUtils;
|
|
|
|
type
|
|
|
|
{ TfrmFileProperties }
|
|
|
|
TfrmFileProperties = class(TForm)
|
|
ButtonPanel: TButtonPanel;
|
|
cbExecGroup: TCheckBox;
|
|
cbExecOther: TCheckBox;
|
|
cbExecOwner: TCheckBox;
|
|
cbReadGroup: TCheckBox;
|
|
cbReadOther: TCheckBox;
|
|
cbReadOwner: TCheckBox;
|
|
cbSgid: TCheckBox;
|
|
cbSticky: TCheckBox;
|
|
cbSuid: TCheckBox;
|
|
cbWriteGroup: TCheckBox;
|
|
cbWriteOther: TCheckBox;
|
|
cbWriteOwner: TCheckBox;
|
|
cbxGroups: TComboBox;
|
|
cbxUsers: TComboBox;
|
|
chkExecutable: TCheckBox;
|
|
chkRecursive: TCheckBox;
|
|
DividerBevel1: TDividerBevel;
|
|
DividerBevel2: TDividerBevel;
|
|
DividerBevel3: TDividerBevel;
|
|
DividerBevel4: TDividerBevel;
|
|
edtOctal: TEdit;
|
|
lblExecutable: TLabel;
|
|
lblFileName: TLabel;
|
|
imgFileIcon: TImage;
|
|
lblFolder: TKASCDEdit;
|
|
lblFolderStr: TLabel;
|
|
lblGroupStr: TLabel;
|
|
lblLastAccess: TKASCDEdit;
|
|
lblLastAccessStr: TLabel;
|
|
lblLastModif: TKASCDEdit;
|
|
lblLastModifStr: TLabel;
|
|
lblLastStChange: TKASCDEdit;
|
|
lblLastStChangeStr: TLabel;
|
|
lblCreated: TKASCDEdit;
|
|
lblCreatedStr: TLabel;
|
|
lblOctal: TLabel;
|
|
lblAttrBitsStr: TLabel;
|
|
lblAttrText: TLabel;
|
|
lblExec: TLabel;
|
|
lblFileStr: TLabel;
|
|
lblFile: TLabel;
|
|
lblAttrGroupStr: TLabel;
|
|
lblAttrOtherStr: TLabel;
|
|
lblAttrOwnerStr: TLabel;
|
|
lblOwnerStr: TLabel;
|
|
|
|
lblRead: TLabel;
|
|
lblSize: TKASCDEdit;
|
|
lblSizeOnDisk: TKASCDEdit;
|
|
lblContains: TKASCDEdit;
|
|
lblSizeStr: TLabel;
|
|
lblSizeOnDiskStr: TLabel;
|
|
lblContainsStr: TLabel;
|
|
lblSymlink: TKASCDEdit;
|
|
lblAttrTextStr: TLabel;
|
|
lblSymlinkStr: TLabel;
|
|
lblMediaType: TKASCDEdit;
|
|
lblMediaTypeStr: TLabel;
|
|
lblType: TKASCDEdit;
|
|
lblTypeStr: TLabel;
|
|
lblLinks: TKASCDEdit;
|
|
lblLinksStr: TLabel;
|
|
lblWrite: TLabel;
|
|
|
|
pnlOwner: TPanel;
|
|
pnlCaption: TPanel;
|
|
pnlData: TPanel;
|
|
pnlIcon: TPanel;
|
|
pcPageControl: TPageControl;
|
|
sgPlugins: TStringGrid;
|
|
tsPlugins: TTabSheet;
|
|
tmUpdateFolderSize: TTimer;
|
|
tsProperties: TTabSheet;
|
|
tsAttributes: TTabSheet;
|
|
procedure cbChangeModeClick(Sender: TObject);
|
|
procedure chkExecutableChange(Sender: TObject);
|
|
procedure edtOctalKeyPress(Sender: TObject; var Key: char);
|
|
procedure edtOctalKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure OKButtonClick(Sender: TObject);
|
|
procedure tmUpdateFolderSizeTimer(Sender: TObject);
|
|
procedure FileSourceOperationStateChangedNotify(Operation: TFileSourceOperation;
|
|
State: TFileSourceOperationState);
|
|
private
|
|
bPerm: Boolean;
|
|
FFileSource: IFileSource;
|
|
FFiles: TFiles;
|
|
FPropertyFormatter: IFilePropertyFormatter;
|
|
FFileSourceCalcStatisticsOperation: TFileSourceCalcStatisticsOperation;
|
|
FChangeTriggersEnabled: Boolean;
|
|
FFileAttr: TFileAttributeData;
|
|
FFileType,
|
|
OriginalAttr: TFileAttrs;
|
|
OriginalUser, OriginalGroup: String;
|
|
FOperation: TFileSourceSetFilePropertyOperation;
|
|
|
|
procedure ShowType(Attrs: TFileAttrs);
|
|
procedure ShowExecutable;
|
|
procedure ShowPermissions(Mode: TFileAttrs);
|
|
function GetModeFromForm(out ExcludeAttrs: TFileAttrs): TFileAttrs;
|
|
function FormatSize(ASize: Int64): String;
|
|
procedure ShowMany;
|
|
procedure ShowFile(iIndex:Integer);
|
|
procedure StartCalcFolderSize;
|
|
procedure StopCalcFolderSize;
|
|
procedure ShowPlugin(iIndex:Integer);
|
|
procedure UpdateAllowGrayed(AllowGrayed: Boolean);
|
|
function FormatUnixAttributesEx(iAttr: TFileAttrs): String;
|
|
public
|
|
constructor Create(AOwner: TComponent; aFileSource: IFileSource; theFiles: TFiles); reintroduce;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
|
|
procedure ShowFileProperties(aFileSource: IFileSource; const aFiles: TFiles);
|
|
|
|
implementation
|
|
|
|
{$R *.lfm}
|
|
|
|
uses
|
|
LCLType, LazUTF8, uLng, BaseUnix, uUsersGroups, uDCUtils,
|
|
uDefaultFilePropertyFormatter, uMyUnix, DCFileAttributes, uGlobs, uWdxModule,
|
|
uFileSourceOperationTypes, uFileSystemFileSource, uOperationsManager, WdxPlugin,
|
|
uFileSourceOperationOptions, uKeyboard, DCStrUtils, uPixMapManager,
|
|
uFileSourceProperty, DCDateTimeUtils, uTypes;
|
|
|
|
procedure ShowFileProperties(aFileSource: IFileSource; const aFiles: TFiles);
|
|
begin
|
|
if aFiles.Count > 0 then
|
|
begin
|
|
with TfrmFileProperties.Create(Application, aFileSource, aFiles) do
|
|
try
|
|
ShowModal;
|
|
finally
|
|
Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
constructor TfrmFileProperties.Create(AOwner: TComponent; aFileSource: IFileSource; theFiles: TFiles);
|
|
var
|
|
ASize: Integer;
|
|
AFiles: TFiles;
|
|
HasAttr: Boolean;
|
|
ActiveFile: TFile;
|
|
aFileProperties: TFileProperties;
|
|
begin
|
|
FFiles := theFiles.Clone;
|
|
FFileSource:= aFileSource;
|
|
FChangeTriggersEnabled := True;
|
|
FPropertyFormatter := MaxDetailsFilePropertyFormatter;
|
|
|
|
ActiveFile:= FFiles[0];
|
|
|
|
HasAttr:= (fspDirectAccess in aFileSource.Properties) and
|
|
(mbFileGetAttr(ActiveFile.FullPath, FFileAttr));
|
|
|
|
if HasAttr then
|
|
begin
|
|
{$IFDEF UNIX}
|
|
if not (fpOwner in ActiveFile.SupportedProperties) then
|
|
begin
|
|
ActiveFile.Properties[fpOwner]:= TFileOwnerProperty.Create;
|
|
end;
|
|
ActiveFile.OwnerProperty.Group:= FFileAttr.FindData.st_gid;
|
|
ActiveFile.OwnerProperty.Owner:= FFileAttr.FindData.st_uid;
|
|
{$ENDIF}
|
|
if fpModificationTime in ActiveFile.SupportedProperties then
|
|
ActiveFile.ModificationTime:= FileTimeToDateTime(DCBasicTypes.TFileTime(FFileAttr.LastWriteTime));
|
|
if fpChangeTime in ActiveFile.SupportedProperties then
|
|
ActiveFile.ChangeTime:= FileTimeToDateTime(DCBasicTypes.TFileTime(FFileAttr.PlatformTime));
|
|
if fpLastAccessTime in ActiveFile.SupportedProperties then
|
|
ActiveFile.LastAccessTime:= FileTimeToDateTime(DCBasicTypes.TFileTime(FFileAttr.LastAccessTime));
|
|
end;
|
|
|
|
if (fsoSetFileProperty in aFileSource.GetOperationsTypes) then
|
|
begin
|
|
AFiles:= FFiles.Clone;
|
|
|
|
FillByte(aFileProperties, SizeOf(aFileProperties), 0);
|
|
if fpAttributes in ActiveFile.SupportedProperties then
|
|
aFileProperties[fpAttributes]:= ActiveFile.Properties[fpAttributes].Clone;
|
|
if fpOwner in ActiveFile.SupportedProperties then
|
|
aFileProperties[fpOwner]:= ActiveFile.Properties[fpOwner].Clone;
|
|
|
|
FOperation:= aFileSource.CreateSetFilePropertyOperation(AFiles,
|
|
aFileProperties) as TFileSourceSetFilePropertyOperation;
|
|
end;
|
|
|
|
inherited Create(AOwner);
|
|
|
|
tsProperties.AutoSize:= True;
|
|
tsAttributes.AutoSize:= True;
|
|
|
|
// Enable only supported file properties
|
|
if Assigned(FOperation) then
|
|
begin
|
|
if fpAttributes in FOperation.SupportedProperties then
|
|
begin
|
|
UpdateAllowGrayed((FFiles.Count > 1) or FFiles[0].IsDirectory);
|
|
end;
|
|
end;
|
|
|
|
ASize:= gIconsSize * Round( Application.MainForm.GetCanvasScaleFactor );
|
|
if ASize > 48 then ASize:= 48;
|
|
imgFileIcon.Width:= ASize;
|
|
imgFileIcon.Height:= ASize;
|
|
|
|
pnlOwner.Enabled:= Assigned(FOperation) and (fpOwner in FOperation.SupportedProperties);
|
|
tsAttributes.Enabled:= Assigned(FOperation) and (fpAttributes in FOperation.SupportedProperties);
|
|
end;
|
|
|
|
destructor TfrmFileProperties.Destroy;
|
|
begin
|
|
FFiles.Free;
|
|
StopCalcFolderSize;
|
|
FreeAndNil( FOperation );
|
|
inherited Destroy;
|
|
FPropertyFormatter := nil; // free interface
|
|
end;
|
|
|
|
function TfrmFileProperties.GetModeFromForm(out ExcludeAttrs: TFileAttrs): TFileAttrs;
|
|
begin
|
|
Result:= 0;
|
|
ExcludeAttrs:= 0;
|
|
case cbReadOwner.State of
|
|
cbChecked: Result:= (Result or S_IRUSR);
|
|
cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IRUSR;
|
|
end;
|
|
case cbWriteOwner.State of
|
|
cbChecked: Result:= (Result or S_IWUSR);
|
|
cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IWUSR;
|
|
end;
|
|
case cbExecOwner.State of
|
|
cbChecked: Result:= (Result or S_IXUSR);
|
|
cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IXUSR;
|
|
end;
|
|
case cbReadGroup.State of
|
|
cbChecked: Result:= (Result or S_IRGRP);
|
|
cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IRGRP;
|
|
end;
|
|
case cbWriteGroup.State of
|
|
cbChecked: Result:= (Result or S_IWGRP);
|
|
cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IWGRP;
|
|
end;
|
|
case cbExecGroup.State of
|
|
cbChecked: Result:= (Result or S_IXGRP);
|
|
cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IXGRP;
|
|
end;
|
|
case cbReadOther.State of
|
|
cbChecked: Result:= (Result or S_IROTH);
|
|
cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IROTH;
|
|
end;
|
|
case cbWriteOther.State of
|
|
cbChecked: Result:= (Result or S_IWOTH);
|
|
cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IWOTH;
|
|
end;
|
|
case cbExecOther.State of
|
|
cbChecked: Result:= (Result or S_IXOTH);
|
|
cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IXOTH;
|
|
end;
|
|
|
|
case cbSuid.State of
|
|
cbChecked: Result:= (Result or S_ISUID);
|
|
cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_ISUID;
|
|
end;
|
|
case cbSgid.State of
|
|
cbChecked: Result:= (Result or S_ISGID);
|
|
cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_ISGID;
|
|
end;
|
|
case cbSticky.State of
|
|
cbChecked: Result:= (Result or S_ISVTX);
|
|
cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_ISVTX;
|
|
end;
|
|
end;
|
|
|
|
function TfrmFileProperties.FormatSize(ASize: Int64): String;
|
|
begin
|
|
if gFileSizeFormat in [fsfByte, fsfPersonalizedByte] then
|
|
Result:= cnvFormatFileSize(ASize)
|
|
else begin
|
|
Result:= Format('%s (%s)', [cnvFormatFileSize(ASize), IntToStrTS(ASize)]);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.ShowMany;
|
|
var
|
|
ASize: Int64;
|
|
AFile: TFile;
|
|
Index: Integer;
|
|
ABitmap: TBitmap;
|
|
UserID: Cardinal;
|
|
Files, Directories: Integer;
|
|
begin
|
|
ASize := 0;
|
|
Files := 0;
|
|
Directories := 0;
|
|
|
|
ABitmap := PixMapManager.GetThemeIcon('edit-copy', gIconsSize);
|
|
if Assigned(ABitmap) then
|
|
begin
|
|
imgFileIcon.Picture.Bitmap := ABitmap;
|
|
ABitmap.Free;
|
|
end;
|
|
|
|
for Index:= 0 to FFiles.Count - 1 do
|
|
begin
|
|
AFile:= FFiles[Index];
|
|
if AFile.IsDirectory then
|
|
Inc(Directories)
|
|
else begin
|
|
Inc(Files);
|
|
Inc(ASize, AFile.Size);
|
|
end;
|
|
end;
|
|
|
|
chkRecursive.Visible:= (Directories > 0);
|
|
DividerBevel4.Visible:= chkRecursive.Visible;
|
|
|
|
if (Directories = 0) then
|
|
begin
|
|
lblSize.Caption := FormatSize(ASize);
|
|
end
|
|
else if (fsoCalcStatistics in FFileSource.GetOperationsTypes) then
|
|
begin
|
|
StartCalcFolderSize // Start calculate folder size operation
|
|
end;
|
|
|
|
// Chown
|
|
if Assigned(FOperation.NewProperties[fpOwner]) then
|
|
begin
|
|
OriginalUser := '*';
|
|
OriginalGroup := '*';
|
|
|
|
// Get current user ID
|
|
UserID := fpGetUID;
|
|
// Only owner or root can change owner
|
|
bPerm := (UserID = FFileAttr.FindData.st_uid) or (UserID = 0);
|
|
|
|
// Owner combo box
|
|
cbxUsers.Text := OriginalUser;
|
|
// Only root can change owner
|
|
cbxUsers.Enabled := (UserID = 0);
|
|
if cbxUsers.Enabled then
|
|
begin
|
|
GetUsers(cbxUsers.Items);
|
|
cbxUsers.Sorted:= False;
|
|
cbxUsers.Items.Insert(0, '*');
|
|
end;
|
|
|
|
// Group combo box
|
|
cbxGroups.Text := OriginalGroup;
|
|
cbxGroups.Enabled := bPerm;
|
|
if bPerm then
|
|
begin
|
|
GetUsrGroups(UserID, cbxGroups.Items);
|
|
cbxGroups.Sorted:= False;
|
|
cbxGroups.Items.Insert(0, '*');
|
|
end;
|
|
end;
|
|
|
|
lblFile.Caption := Format(rsPropsContains, [Files, Directories]);
|
|
lblFileName.Caption := lblFile.Caption;
|
|
|
|
lblContains.Visible:= (Directories > 0);
|
|
lblContainsStr.Visible:= (Directories > 0);
|
|
|
|
lblMediaType.Visible:= False;
|
|
lblMediaTypeStr.Visible:= False;
|
|
|
|
lblSizeOnDisk.Visible:= False;
|
|
lblSizeOnDiskStr.Visible:= False;
|
|
|
|
lblSymlink.Visible:= False;
|
|
lblSymlinkStr.Visible:= False;
|
|
|
|
lblLinks.Visible:= False;
|
|
lblLinksStr.Visible:= False;
|
|
|
|
lblLastAccess.Visible:= False;
|
|
lblLastAccessStr.Visible:= False;
|
|
lblLastModif.Visible:= False;
|
|
lblLastModifStr.Visible:= False;
|
|
lblLastStChange.Visible:= False;
|
|
lblLastStChangeStr.Visible:= False;
|
|
lblCreated.Visible := False;
|
|
lblCreatedStr.Visible := False;
|
|
|
|
lblFolder.Caption:= FFiles.Path;
|
|
|
|
lblExecutable.Visible:= False;
|
|
chkExecutable.Visible:= False;
|
|
|
|
FFileType:= FFiles[0].Attributes and S_IFMT;
|
|
|
|
for Index:= 1 to FFiles.Count - 1 do
|
|
begin
|
|
if (FFileType <> (FFiles[Index].Attributes and S_IFMT)) then
|
|
begin
|
|
lblType.Caption:= rsPropsMultipleTypes;
|
|
Exit;
|
|
end;
|
|
end;
|
|
ShowType(FFileType);
|
|
end;
|
|
|
|
procedure TfrmFileProperties.cbChangeModeClick(Sender: TObject);
|
|
var
|
|
AMode, ExcludeAttrs: TFileAttrs;
|
|
CheckBox: TCheckBox absolute Sender;
|
|
begin
|
|
if fsCreating in FormState then exit;
|
|
if FChangeTriggersEnabled then
|
|
begin
|
|
FChangeTriggersEnabled := False;
|
|
if CheckBox.State = cbGrayed then
|
|
begin
|
|
edtOctal.Text:= EmptyStr;
|
|
lblAttrText.Caption:= EmptyStr;
|
|
end
|
|
else begin
|
|
AMode:= GetModeFromForm(ExcludeAttrs);
|
|
edtOctal.Text:= DecToOct(AMode);
|
|
lblAttrText.Caption:= FormatUnixAttributesEx(AMode);
|
|
end;
|
|
FChangeTriggersEnabled := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.chkExecutableChange(Sender: TObject);
|
|
begin
|
|
if chkExecutable.Tag = 0 then
|
|
begin
|
|
chkExecutable.Tag:= 1;
|
|
case chkExecutable.State of
|
|
cbChecked,
|
|
cbUnchecked:
|
|
begin
|
|
cbExecOwner.Checked:= chkExecutable.Checked;
|
|
cbExecGroup.Checked:= chkExecutable.Checked;
|
|
cbExecOther.Checked:= chkExecutable.Checked;
|
|
end;
|
|
cbGrayed:
|
|
begin
|
|
cbExecOwner.Checked:= ((OriginalAttr and S_IXUSR) = S_IXUSR);
|
|
cbExecGroup.Checked:= ((OriginalAttr and S_IXGRP) = S_IXGRP);
|
|
cbExecOther.Checked:= ((OriginalAttr and S_IXOTH) = S_IXOTH);
|
|
end;
|
|
end;
|
|
chkExecutable.Tag:= 0;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.edtOctalKeyPress(Sender: TObject; var Key: char);
|
|
begin
|
|
if not ((Key in ['0'..'7']) or (Key = Chr(VK_BACK)) or (Key = Chr(VK_DELETE))) then
|
|
Key:= #0;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.edtOctalKeyUp(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
var
|
|
AMode: TFileAttrs;
|
|
begin
|
|
if FChangeTriggersEnabled then
|
|
begin
|
|
FChangeTriggersEnabled := False;
|
|
AMode:= OctToDec(edtOctal.Text);
|
|
lblAttrText.Caption := FormatUnixAttributesEx(AMode);
|
|
ShowPermissions(AMode);
|
|
FChangeTriggersEnabled := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.ShowPermissions(Mode: TFileAttrs);
|
|
begin
|
|
cbReadOwner.Checked:= ((Mode AND S_IRUSR) = S_IRUSR);
|
|
cbWriteOwner.Checked:= ((Mode AND S_IWUSR) = S_IWUSR);
|
|
cbExecOwner.Checked:= ((Mode AND S_IXUSR) = S_IXUSR);
|
|
|
|
cbReadGroup.Checked:= ((Mode AND S_IRGRP) = S_IRGRP);
|
|
cbWriteGroup.Checked:= ((Mode AND S_IWGRP) = S_IWGRP);
|
|
cbExecGroup.Checked:= ((Mode AND S_IXGRP) = S_IXGRP);
|
|
|
|
cbReadOther.Checked:= ((Mode AND S_IROTH) = S_IROTH);
|
|
cbWriteOther.Checked:= ((Mode AND S_IWOTH) = S_IWOTH);
|
|
cbExecOther.Checked:= ((Mode AND S_IXOTH) = S_IXOTH);
|
|
|
|
cbSuid.Checked:= ((Mode AND S_ISUID) = S_ISUID);
|
|
cbSgid.Checked:= ((Mode AND S_ISGID) = S_ISGID);
|
|
cbSticky.Checked:= ((Mode AND S_ISVTX) = S_ISVTX);
|
|
|
|
ShowExecutable;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.ShowFile(iIndex:Integer);
|
|
var
|
|
Idx: PtrInt;
|
|
ASize: Int64;
|
|
UserID: Cardinal;
|
|
hasSize: Boolean;
|
|
ABitmap: TBitmap;
|
|
Attrs: TFileAttrs;
|
|
AMimeType: String;
|
|
isFileSystem: Boolean;
|
|
begin
|
|
isFileSystem := FFileSource.IsClass(TFileSystemFileSource);
|
|
|
|
Idx := PixMapManager.GetIconByFile(FFiles[iIndex], isFileSystem, True, sim_all_and_exe, True);
|
|
if Idx < 0 then Idx:= PixMapManager.GetDefaultIcon(FFiles[iIndex]);
|
|
ABitmap:= PixMapManager.GetBitmap(Idx);
|
|
imgFileIcon.Picture.Bitmap := ABitmap;
|
|
ABitmap.Free;
|
|
|
|
with FFiles[iIndex] do
|
|
begin
|
|
lblFileName.Caption:= Name;
|
|
lblFile.Caption:= Name;
|
|
lblFolder.Caption:= Path;
|
|
|
|
if not (fpCreationTime in SupportedProperties) then
|
|
begin
|
|
if fpCreationTime in FFileSource.RetrievableFileProperties then
|
|
begin
|
|
FFileSource.RetrieveProperties(FFiles[iIndex], [fpCreationTime], []);
|
|
end;
|
|
end;
|
|
|
|
// Size
|
|
hasSize := (fpSize in SupportedProperties) and (not IsLinkToDirectory);
|
|
if hasSize then
|
|
begin
|
|
if IsDirectory and (fsoCalcStatistics in FFileSource.GetOperationsTypes) then
|
|
StartCalcFolderSize // Start calculate folder size operation
|
|
else
|
|
lblSize.Caption := FormatSize(Size);
|
|
end;
|
|
lblSize.Visible := hasSize;
|
|
lblSizeStr.Visible := hasSize;
|
|
lblContains.Visible:= IsDirectory;
|
|
lblContainsStr.Visible:= IsDirectory;
|
|
|
|
// Size on disk
|
|
hasSize:= (fpAttributes in SupportedProperties) and (FPS_ISREG(Attributes)) and
|
|
(FFileAttr.FindData.st_ino <> 0);
|
|
|
|
if hasSize then
|
|
begin
|
|
ASize:= FFileAttr.FindData.st_blocks * 512;
|
|
lblSizeOnDisk.Caption:= FormatSize(ASize);
|
|
end;
|
|
lblSizeOnDisk.Visible:= hasSize;
|
|
lblSizeOnDiskStr.Visible:= hasSize;
|
|
|
|
// Links
|
|
lblLinks.Visible:= isFileSystem and (FPS_ISREG(Attributes)) and (FFileAttr.FindData.st_nlink > 1);
|
|
if lblLinks.Visible then lblLinks.Caption:= IntToStrTS(FFileAttr.FindData.st_nlink);
|
|
lblLinksStr.Visible:= lblLinks.Visible;
|
|
|
|
// Times
|
|
lblLastAccess.Visible := fpLastAccessTime in SupportedProperties;
|
|
lblLastAccessStr.Visible := fpLastAccessTime in SupportedProperties;
|
|
if fpLastAccessTime in SupportedProperties then
|
|
lblLastAccess.Caption := Properties[fpLastAccessTime].Format(FPropertyFormatter)
|
|
else
|
|
lblLastAccess.Caption := '';
|
|
|
|
lblLastStChange.Visible := fpChangeTime in SupportedProperties;
|
|
lblLastStChangeStr.Visible := fpChangeTime in SupportedProperties;
|
|
if fpChangeTime in SupportedProperties then
|
|
lblLastStChange.Caption := Properties[fpChangeTime].Format(FPropertyFormatter)
|
|
else
|
|
lblLastStChange.Caption := '';
|
|
|
|
lblLastModif.Visible := fpModificationTime in SupportedProperties;
|
|
lblLastModifStr.Visible := fpModificationTime in SupportedProperties;
|
|
if fpModificationTime in SupportedProperties then
|
|
lblLastModif.Caption := Properties[fpModificationTime].Format(FPropertyFormatter)
|
|
else
|
|
lblLastModif.Caption := '';
|
|
|
|
lblCreated.Visible := fpCreationTime in SupportedProperties;
|
|
lblCreatedStr.Visible := fpCreationTime in SupportedProperties;
|
|
if fpCreationTime in SupportedProperties then
|
|
lblCreated.Caption := Properties[fpCreationTime].Format(FPropertyFormatter)
|
|
else
|
|
lblCreated.Caption := '';
|
|
|
|
// Chown
|
|
if fpOwner in SupportedProperties then
|
|
begin
|
|
OriginalUser := UIDToStr(OwnerProperty.Owner);
|
|
OriginalGroup := GIDToStr(OwnerProperty.Group);
|
|
|
|
// Get current user ID
|
|
UserID := fpGetUID;
|
|
// Only owner or root can change owner
|
|
bPerm := (UserID = OwnerProperty.Owner) or (UserID = 0);
|
|
|
|
// Owner combo box
|
|
cbxUsers.Text := OriginalUser;
|
|
// Only root can change owner
|
|
cbxUsers.Enabled := (UserID = 0);
|
|
if cbxUsers.Enabled then GetUsers(cbxUsers.Items);
|
|
|
|
// Group combo box
|
|
cbxGroups.Text := OriginalGroup;
|
|
cbxGroups.Enabled := bPerm;
|
|
if bPerm then GetUsrGroups(UserID, cbxGroups.Items);
|
|
end;
|
|
|
|
// MIME type
|
|
hasSize:= isFileSystem;
|
|
if hasSize then
|
|
begin
|
|
AMimeType:= GetFileMimeType(FullPath);
|
|
hasSize:= Length(AMimeType) > 0;
|
|
lblMediaType.Caption:= AMimeType;
|
|
end;
|
|
lblMediaType.Visible:= hasSize;
|
|
lblMediaTypeStr.Visible:= hasSize;
|
|
|
|
// Attributes
|
|
if fpAttributes in SupportedProperties then
|
|
begin
|
|
Attrs := AttributesProperty.Value;
|
|
FFileType:= Attrs and S_IFMT;
|
|
OriginalAttr := Attrs and $0FFF;
|
|
|
|
ShowPermissions(Attrs);
|
|
|
|
lblExecutable.Visible:= FPS_ISREG(Attrs);
|
|
chkExecutable.Visible:= lblExecutable.Visible;
|
|
lblAttrText.Caption := Properties[fpAttributes].Format(DefaultFilePropertyFormatter);
|
|
|
|
ShowType(Attrs);
|
|
|
|
chkRecursive.Visible := IsDirectory;
|
|
DividerBevel4.Visible:= chkRecursive.Visible;
|
|
|
|
lblSymlink.Visible := FPS_ISLNK(Attrs);
|
|
lblSymlinkStr.Visible := lblSymlink.Visible;
|
|
if lblSymlink.Visible then
|
|
begin
|
|
if isFileSystem then
|
|
lblSymlink.Caption := ReadSymLink(FullPath)
|
|
else if (Assigned(LinkProperty) and LinkProperty.IsValid) then
|
|
lblSymlink.Caption := LinkProperty.LinkTo
|
|
else begin
|
|
lblSymlink.Visible := False;
|
|
lblSymlinkStr.Visible := False;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
chkRecursive.Visible:= False;
|
|
DividerBevel4.Visible:= False;
|
|
edtOctal.Text:= rsMsgErrNotSupported;
|
|
lblAttrText.Caption:= rsMsgErrNotSupported;
|
|
lblType.Caption:= rsPropsUnknownType;
|
|
lblSymlink.Caption:= '';
|
|
end;
|
|
end;
|
|
|
|
tsPlugins.Visible:= isFileSystem;
|
|
if isFileSystem then ShowPlugin(iIndex);
|
|
end;
|
|
|
|
procedure TfrmFileProperties.FormCreate(Sender: TObject);
|
|
begin
|
|
InitPropStorage(Self);
|
|
|
|
if (FFiles.Count = 1) then
|
|
ShowFile(0)
|
|
else begin
|
|
ShowMany;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.FormKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
begin
|
|
case Key of
|
|
VK_TAB:
|
|
begin
|
|
if Shift * KeyModifiersShortcut = [ssCtrl] then
|
|
begin
|
|
pcPageControl.SelectNextPage(True);
|
|
Key := 0;
|
|
end
|
|
else if Shift * KeyModifiersShortcut = [ssCtrl, ssShift] then
|
|
begin
|
|
pcPageControl.SelectNextPage(False);
|
|
Key := 0;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.OKButtonClick(Sender: TObject);
|
|
var
|
|
theNewProperties: TFileProperties;
|
|
begin
|
|
if Assigned(FOperation) then
|
|
begin
|
|
with FOperation do
|
|
begin
|
|
theNewProperties:= NewProperties;
|
|
if fpAttributes in SupportedProperties then
|
|
begin
|
|
if theNewProperties[fpAttributes] is TUnixFileAttributesProperty then
|
|
IncludeAttributes:= GetModeFromForm(ExcludeAttributes);
|
|
// Nothing changed, clear new property
|
|
if (IncludeAttributes = 0) and (ExcludeAttributes = 0) then
|
|
begin
|
|
theNewProperties[fpAttributes].Free;
|
|
theNewProperties[fpAttributes]:= nil;
|
|
end;
|
|
end;
|
|
if fpOwner in SupportedProperties then
|
|
begin
|
|
if (OriginalUser <> cbxUsers.Text) or (OriginalGroup <> cbxGroups.Text) then
|
|
begin
|
|
TFileOwnerProperty(theNewProperties[fpOwner]).Owner:= StrToUID(cbxUsers.Text);
|
|
TFileOwnerProperty(theNewProperties[fpOwner]).Group:= StrToGID(cbxGroups.Text);
|
|
end
|
|
// Nothing changed, clear new property
|
|
else begin
|
|
theNewProperties[fpOwner].Free;
|
|
theNewProperties[fpOwner]:= nil;
|
|
end;
|
|
end;
|
|
NewProperties:= theNewProperties;
|
|
Recursive:= chkRecursive.Checked;
|
|
end;
|
|
OperationsManager.AddOperation(FOperation);
|
|
FOperation:= nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.tmUpdateFolderSizeTimer(Sender: TObject);
|
|
begin
|
|
if Assigned(FFileSourceCalcStatisticsOperation) then
|
|
with FFileSourceCalcStatisticsOperation.RetrieveStatistics do
|
|
begin
|
|
lblSize.Caption := FormatSize(Size);
|
|
lblContains.Caption := Format(rsPropsContains, [Files, Directories]);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.FileSourceOperationStateChangedNotify(
|
|
Operation: TFileSourceOperation; State: TFileSourceOperationState);
|
|
begin
|
|
if Assigned(FFileSourceCalcStatisticsOperation) and (State = fsosStopped) then
|
|
begin
|
|
tmUpdateFolderSize.Enabled:= False;
|
|
tmUpdateFolderSizeTimer(tmUpdateFolderSize);
|
|
FFileSourceCalcStatisticsOperation := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.ShowType(Attrs: TFileAttrs);
|
|
begin
|
|
if FPS_ISDIR(Attrs) then
|
|
lblType.Caption:= rsPropsFolder
|
|
{$IFDEF UNIX}
|
|
else if FPS_ISREG(Attrs) then
|
|
lblType.Caption:= rsPropsFile
|
|
else if FPS_ISCHR(Attrs) then
|
|
lblType.Caption:= rsPropsSpChrDev
|
|
else if FPS_ISBLK(Attrs) then
|
|
lblType.Caption:= rsPropsSpBlkDev
|
|
else if FPS_ISFIFO(Attrs) then
|
|
lblType.Caption:= rsPropsNmdPipe
|
|
else if FPS_ISLNK(Attrs) then
|
|
lblType.Caption:= rsPropsSymLink
|
|
else if FPS_ISSOCK(Attrs) then
|
|
lblType.Caption:= rsPropsSocket
|
|
{$ENDIF}
|
|
else
|
|
lblType.Caption:= rsPropsUnknownType;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.ShowExecutable;
|
|
begin
|
|
if chkExecutable.Tag = 0 then
|
|
begin
|
|
if cbExecOwner.Checked and cbExecGroup.Checked and cbExecOther.Checked then
|
|
chkExecutable.State:= cbChecked
|
|
else if not (cbExecOwner.Checked or cbExecGroup.Checked or cbExecOther.Checked) then
|
|
chkExecutable.State:= cbUnchecked
|
|
else begin
|
|
chkExecutable.AllowGrayed:= True;
|
|
chkExecutable.State:= cbGrayed;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.StartCalcFolderSize;
|
|
var
|
|
aFiles: TFiles;
|
|
begin
|
|
aFiles:= FFiles.Clone;
|
|
try
|
|
FFileSourceCalcStatisticsOperation:= FFileSource.CreateCalcStatisticsOperation(aFiles) as TFileSourceCalcStatisticsOperation;
|
|
if Assigned(FFileSourceCalcStatisticsOperation) then
|
|
begin
|
|
FFileSourceCalcStatisticsOperation.SkipErrors:= True;
|
|
FFileSourceCalcStatisticsOperation.SymLinkOption:= fsooslDontFollow;
|
|
FFileSourceCalcStatisticsOperation.AddStateChangedListener([fsosStopped], @FileSourceOperationStateChangedNotify);
|
|
OperationsManager.AddOperation(FFileSourceCalcStatisticsOperation, False);
|
|
tmUpdateFolderSize.Enabled:= True;
|
|
end;
|
|
finally
|
|
aFiles.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.StopCalcFolderSize;
|
|
begin
|
|
if Assigned(FFileSourceCalcStatisticsOperation) then
|
|
begin
|
|
tmUpdateFolderSize.Enabled:= False;
|
|
FFileSourceCalcStatisticsOperation.Stop;
|
|
end;
|
|
FFileSourceCalcStatisticsOperation:= nil;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.ShowPlugin(iIndex: Integer);
|
|
var
|
|
I, J: Integer;
|
|
Value: String;
|
|
Index: Integer;
|
|
FileName: String;
|
|
WdxModule: TWdxModule;
|
|
begin
|
|
FileName:= FFiles[iIndex].FullPath;
|
|
Value:= LowerCase(FFiles[iIndex].Extension);
|
|
|
|
for Index:= 0 to gWdxPlugins.Count - 1 do
|
|
begin
|
|
WdxModule:= gWdxPlugins.GetWdxModule(Index);
|
|
if (Length(WdxModule.DetectStr) > 0) and WdxModule.FileParamVSDetectStr(FFiles[iIndex]) then
|
|
begin
|
|
if not gWdxPlugins.IsLoaded(Index) then
|
|
begin
|
|
if not gWdxPlugins.LoadModule(Index) then
|
|
Continue;
|
|
end;
|
|
J:= 0;
|
|
sgPlugins.RowCount:= WdxModule.FieldList.Count + 1;
|
|
for I:= 0 to WdxModule.FieldList.Count - 1 do
|
|
begin
|
|
if not (TWdxField(WdxModule.FieldList.Objects[I]).FType in [ft_fulltext, ft_fulltextw]) then
|
|
begin
|
|
Value:= WdxModule.CallContentGetValue(FileName, I, 0, CONTENT_DELAYIFSLOW);
|
|
if (Length(Value) > 0) then
|
|
begin
|
|
Inc(J);
|
|
sgPlugins.Cells[1, J]:= Value;
|
|
sgPlugins.Cells[0, J]:= TWdxField(WdxModule.FieldList.Objects[I]).LName;
|
|
end;
|
|
end;
|
|
end;
|
|
sgPlugins.RowCount:= J + 1;
|
|
tsPlugins.TabVisible:= J > 0;
|
|
if tsPlugins.TabVisible then Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmFileProperties.UpdateAllowGrayed(AllowGrayed: Boolean);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
for Index:= 0 to tsAttributes.ControlCount - 1 do
|
|
begin
|
|
if tsAttributes.Controls[Index] is TCheckBox then
|
|
TCheckBox(tsAttributes.Controls[Index]).AllowGrayed:= AllowGrayed;
|
|
end;
|
|
end;
|
|
|
|
function TfrmFileProperties.FormatUnixAttributesEx(iAttr: TFileAttrs): String;
|
|
begin
|
|
if (FFiles.Count = 1) then
|
|
Result:= FormatUnixAttributes(FFileType or iAttr)
|
|
else begin
|
|
Result:= Copy(FormatUnixAttributes(iAttr), 2, MaxInt);
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|