summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@users.sourceforge.net>2010-02-14 15:12:08 +0100
committerTomas Bzatek <tbzatek@users.sourceforge.net>2010-02-14 15:12:08 +0100
commitd338f1f0c1a72665396d95bfe303ed408a3f10b9 (patch)
treec41c71b380e1b749a49518a57edd3453a3733a5f
parent55605a80092452ce593cb05df12a404ad47aa808 (diff)
downloadtuxcmd-d338f1f0c1a72665396d95bfe303ed408a3f10b9.tar.xz
Show warning when some files are unreadablev0.6.76
This will make user aware of what files will not be copied, chmodded or chowned.
-rw-r--r--UConfig.pas4
-rw-r--r--UCore.pas9
-rw-r--r--UCoreUtils.pas2
-rw-r--r--UCoreWorkers.pas298
-rw-r--r--UGnome.pas61
5 files changed, 246 insertions, 128 deletions
diff --git a/UConfig.pas b/UConfig.pas
index b9d85f9..963dc3a 100644
--- a/UConfig.pas
+++ b/UConfig.pas
@@ -25,8 +25,8 @@ uses Classes, ULocale;
resourcestring
ConstAppTitle = 'Tux Commander';
- ConstAboutVersion = '0.6.75-dev';
- ConstAboutBuildDate = '2009-12-16';
+ ConstAboutVersion = '0.6.76-dev';
+ ConstAboutBuildDate = '2010-02-14';
{$IFDEF FPC}
{$INCLUDE fpcver.inc}
diff --git a/UCore.pas b/UCore.pas
index b4425c3..cc6929f 100644
--- a/UCore.pas
+++ b/UCore.pas
@@ -28,7 +28,7 @@ function FillPanel(List: TList; ListView: TGTKListView; Engine: TPanelEngine; Le
procedure FindNextSelected(ListView: TGTKListView; DataList: TList; var Item1, Item2: string);
procedure UnselectAll(ListView: TGTKListView; DataList: TList);
-procedure FillDirFiles(Engine: TPanelEngine; DestList: TList; InputFiles: TStringList; DoNotRecurse, SortForStream: boolean);
+procedure FillDirFiles(Engine: TPanelEngine; DestList: TList; InputFiles: TStringList; DoNotRecurse, SortForStream: boolean; InaccessiblePaths: TStringList);
function GetFileInfoSL(Engine: TPanelEngine; const APath: string): PDataItemSL;
procedure DebugWriteListSL(List: TList);
@@ -348,7 +348,7 @@ end;
(********************************************************************************************************************************)
(********************************************************************************************************************************)
-procedure FillDirFiles(Engine: TPanelEngine; DestList: TList; InputFiles: TStringList; DoNotRecurse, SortForStream: boolean);
+procedure FillDirFiles(Engine: TPanelEngine; DestList: TList; InputFiles: TStringList; DoNotRecurse, SortForStream: boolean; InaccessiblePaths: TStringList);
var DirStage1List, FilesList, DirStage2List: TList;
function FillDirFiles_compare_func(Item1, Item2: Pointer): integer;
@@ -442,7 +442,7 @@ var DirStage1List, FilesList, DirStage2List: TList;
if Engine.ChangeDir(ParentDir, @Error) then
FillDirFiles_Recurse(ParentDir, ALevel + 1)
else begin
- // * TODO: report and handle errors? we should make sure that user knows some of his data won't be copied
+ InaccessiblePaths.Add(ParentDir);
DebugMsg(['*** FillDirFiles_Recurse: error changing dir to ''', LocalPath, ''': ', Error^.message]);
g_error_free(Error);
end;
@@ -454,7 +454,7 @@ var DirStage1List, FilesList, DirStage2List: TList;
end;
end;
end else begin
- // * TODO: report and handle errors? we should make sure that user knows some of his data won't be copied
+ InaccessiblePaths.Add(LocalPath);
DebugMsg(['*** FillDirFiles_Recurse: error getting listing of ''', LocalPath, ''': ', Error^.message]);
g_error_free(Error);
// Clear remaining items (in case of error)
@@ -477,6 +477,7 @@ begin
for i := 0 to InputFiles.Count - 1 do begin
root := GetFileInfoSL(Engine, InputFiles[i]);
if (root = nil) then begin
+ InaccessiblePaths.Add(InputFiles[i]);
DebugMsg(['FillDirFiles: cannot stat ', InputFiles[i]]);
Exit;
end;
diff --git a/UCoreUtils.pas b/UCoreUtils.pas
index 342d796..d65eed4 100644
--- a/UCoreUtils.pas
+++ b/UCoreUtils.pas
@@ -824,7 +824,7 @@ begin
if (libGnomeUI2Handle = nil) or (@gnome_about_new = nil)
then Application.MessageBox(Format(LANGAboutString, [ConstAboutVersion, ConstAboutBuildDate]))
else begin
- AboutBox := gnome_about_new('Tux Commander', nil, 'Copyright © 2009 Tomáš Bžatek',
+ AboutBox := gnome_about_new('Tux Commander', nil, 'Copyright © 2010 Tomáš Bžatek',
PChar(Format(LANGAboutStringGnome, [ConstAboutVersion, ConstAboutBuildDate])),
@Authors, nil, Translations, AppIcon128.FPixbuf);
gtk_window_set_transient_for(GTK_WINDOW(AboutBox), GTK_WINDOW(FMain.FWidget));
diff --git a/UCoreWorkers.pas b/UCoreWorkers.pas
index 3fb394a..00b0672 100644
--- a/UCoreWorkers.pas
+++ b/UCoreWorkers.pas
@@ -85,8 +85,8 @@ type TVFSCallbackThread = class(TThread)
// Dialogs
FCancelMessage: string;
FShowCancelMessage,
- FDialogShowDirDelete, FDialogShowOverwrite, FDialogShowNewDir, FDialogShowMsgBox: boolean;
- FDialogResultDirDelete, FDialogResultOverwrite, FDialogResultNewDir: integer;
+ FDialogShowDirDelete, FDialogShowOverwrite, FDialogShowNewDir, FDialogShowMsgBox, FDialogShowInaccessible: boolean;
+ FDialogResultDirDelete, FDialogResultOverwrite, FDialogResultNewDir, FDialogResultInaccessible: integer;
FProgress1Pos, FProgress2Pos, FProgress1Max, FProgress2Max: Int64;
FProgress1Text, FProgress2Text, FLabel1Text, FLabel2Text: string;
@@ -102,6 +102,8 @@ type TVFSCallbackThread = class(TThread)
FOverwriteSourceItem, FOverwriteDestItem: PDataItem;
FOverwriteSourceFile, FOverwriteDestFile, FOverwriteRenameStr: string;
+ FInaccessiblePaths: TStringList;
+
FNewDirCaption, FNewDirLabel, FNewDirEdit: string;
FMsgBoxText: string;
@@ -117,6 +119,7 @@ type TVFSCallbackThread = class(TThread)
procedure UpdateCaption2(const CaptionText: string);
function ShowDirDeleteDialog(ButtonsType: TFDirDeleteButtonSet; const Title, FileName: string; Error: PGError): integer;
function ShowOverwriteDialog(ShowAppend: boolean; SourceItem, DestItem: PDataItem; const SourceFile, DestFile: string; var RenameStr: string): integer;
+ function ShowInaccessibleDialog(InaccessiblePaths: TStringList): integer;
function ShowNewDirDialog(Caption, LabelCaption, Edit: string): integer;
function ShowMessageBox(const Text: string; Buttons: TMessageButtons; Style: TMessageStyle;
Default, Escape: TMessageButton): TMessageButton;
@@ -167,7 +170,7 @@ type TVFSCallbackThread = class(TThread)
constructor Create;
destructor Destroy; override;
- procedure PrepareJobFilesFromPanel(AList: TList; DoNotRecurse: boolean);
+ procedure PrepareJobFilesFromPanel(AList: TList; InaccessiblePaths: TStringList; DoNotRecurse: boolean);
end;
@@ -411,6 +414,7 @@ begin
FDialogShowOverwrite := False;
FDialogShowNewDir := False;
FDialogShowMsgBox := False;
+ FDialogShowInaccessible := False;
ErrorHappened := False;
FGUIChanged := False;
FCopyProgressFunc := nil;
@@ -526,6 +530,16 @@ begin
RenameStr := FOverwriteRenameStr;
end;
+function TWorkerThread.ShowInaccessibleDialog(InaccessiblePaths: TStringList): integer;
+begin
+ FDialogResultInaccessible := 0;
+ FInaccessiblePaths := InaccessiblePaths;
+ FDialogShowInaccessible := True;
+ FCallbackLockEvent.ResetEvent;
+ FCallbackLockEvent.WaitFor(INFINITE);
+ Result := FDialogResultInaccessible;
+end;
+
function TWorkerThread.ShowNewDirDialog(Caption, LabelCaption, Edit: string): integer;
begin
FNewDirCaption := Caption;
@@ -552,7 +566,7 @@ end;
(********************************************************************************************************************************)
-procedure TWorkerThread.PrepareJobFilesFromPanel(AList: TList; DoNotRecurse: boolean);
+procedure TWorkerThread.PrepareJobFilesFromPanel(AList: TList; InaccessiblePaths: TStringList; DoNotRecurse: boolean);
var i: longint;
CurrPath: string;
InputFiles: TStringList;
@@ -569,7 +583,7 @@ begin
if (InputFiles.Count = 0) and Assigned(SelectedItem) and (not SelectedItem^.UpDir) then
InputFiles.Add(CurrPath + String(SelectedItem^.FName));
- FillDirFiles(AEngine, AList, InputFiles, DoNotRecurse, True);
+ FillDirFiles(AEngine, AList, InputFiles, DoNotRecurse, True, InaccessiblePaths);
InputFiles.Free;
end;
@@ -737,6 +751,12 @@ begin
b := True;
end;
+ if FDialogShowInaccessible then begin
+ FDialogResultInaccessible := ShowInaccessiblePathsDialog(ParentDialogForm.FWidget, FInaccessiblePaths);
+ FDialogShowInaccessible := False;
+ b := True;
+ end;
+
if FDialogShowNewDir then begin
AFNewDir := nil;
try
@@ -831,6 +851,7 @@ var SkipAll: boolean;
var i: longint;
AList: TList;
+ InaccessiblePaths: TStringList;
CurrPath: string;
Fr: Single;
Response: integer;
@@ -838,13 +859,16 @@ var i: longint;
begin
SkipAll := False;
AList := TList.Create;
+ InaccessiblePaths := TStringList.Create;
CurrPath := IncludeTrailingPathDelimiter(AEngine.Path);
- PrepareJobFilesFromPanel(AList, False);
+ PrepareJobFilesFromPanel(AList, InaccessiblePaths, False);
// * TODO: catch the error
if not AEngine.ChangeDir(CurrPath, nil) then
DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour might occur.']);
libc_chdir('/');
+ // * TODO: show warning about inaccessible paths before deletion starts?
+
SetProgress1Params(AList.Count);
CommitGUIUpdate;
DeleteAll := False;
@@ -889,6 +913,7 @@ begin
for i := AList.Count - 1 downto 0 do FreeDataItem(PDataItemSL(AList[i]));
AList.Clear;
AList.Free;
+ InaccessiblePaths.Free;
// * TODO: catch the error
if not AEngine.ChangeDir(CurrPath, nil) then
DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour might occur.']);
@@ -1363,7 +1388,7 @@ var DefResponse: integer; // Global variables for this function
// Can be called only once, otherwise sorting will fail and extract errors may appear
// TODO: make this universal
// TODO: this is complete mess, make it more clear
- procedure HandleProcessPattern(AList: TList; CurrPath, FullPath, ParamFileName: string; ParamDir, Ren: boolean);
+ procedure HandleProcessPattern(AList: TList; InaccessiblePaths: TStringList; CurrPath, FullPath, ParamFileName: string; ParamDir, Ren: boolean);
var s, s2: string;
b, CaseInsensitiveRename: boolean;
Info: PDataItemSL;
@@ -1390,7 +1415,9 @@ var DefResponse: integer; // Global variables for this function
then begin
Info := GetFileInfoSL(SrcEngine, FullPath);
if Info = nil then begin
+ InaccessiblePaths.Add(FullPath);
DebugMsg(['$$$ Copy: Something went wrong while building the filelist...']);
+ // TODO: ?
ErrorHappened := True;
end else begin
Info^.ADestination := strdup(PChar(s));
@@ -1399,17 +1426,19 @@ var DefResponse: integer; // Global variables for this function
end;
end else InputFiles.Add(FullPath);
end;
- FillDirFiles(SrcEngine, AList, InputFiles, False, True);
+ FillDirFiles(SrcEngine, AList, InputFiles, False, True, InaccessiblePaths);
InputFiles.Free;
end;
var i: longint;
List: TList;
+ InaccessiblePaths: TStringList;
CurrPath, SaveDestPath, SaveSrcPath, s: string;
StartPassed: boolean;
+ SkipInaccessible: boolean;
begin
List := TList.Create;
- List.Clear;
+ InaccessiblePaths := TStringList.Create;
ErrorHappened := False;
SaveSrcPath := '';
CurrPath := IncludeTrailingPathDelimiter(SrcEngine.Path);
@@ -1419,36 +1448,36 @@ begin
// Prepare list of files to copy
if JobType = WORKER_JOB_EXTRACT_TO_TEMP then begin
- if not ExtractFromVFSAll then HandleProcessPattern(List, CurrPath, ExtractFile, ExtractFileName(ExtractFile), False, False)
+ if not ExtractFromVFSAll then HandleProcessPattern(List, InaccessiblePaths, CurrPath, ExtractFile, ExtractFileName(ExtractFile), False, False)
else begin
SaveSrcPath := IncludeTrailingPathDelimiter(SrcEngine.Path);
SrcEngine.SetPath('/');
CurrPath := '/';
- HandleProcessPattern(List, '/', '/', '', True, False);
+ HandleProcessPattern(List, InaccessiblePaths, '/', '/', '', True, False);
end;
end else
if QuickRenameDataItem <> nil then begin // Quick-Rename
with QuickRenameDataItem^ do
- HandleProcessPattern(List, CurrPath, CurrPath + String(FName), String(FName), IsDir and (not IsLnk), True);
+ HandleProcessPattern(List, InaccessiblePaths, CurrPath, CurrPath + String(FName), String(FName), IsDir and (not IsLnk), True);
end else begin // Not Quick-Rename
if JobType <> WORKER_JOB_EXTRACT_TO_TEMP then begin
if DataList.Count > 0 then
for i := 0 to DataList.Count - 1 do
with PDataItem(DataList[i])^ do
if (not UpDir) and Selected
- then HandleProcessPattern(List, CurrPath, CurrPath + String(FName), String(FName), IsDir and (not IsLnk), JobType = WORKER_JOB_MOVE);
+ then HandleProcessPattern(List, InaccessiblePaths, CurrPath, CurrPath + String(FName), String(FName), IsDir and (not IsLnk), JobType = WORKER_JOB_MOVE);
if (List.Count = 0) and Assigned(SelectedItem) and (not SelectedItem^.UpDir) then
with SelectedItem^ do
- HandleProcessPattern(List, CurrPath, CurrPath + String(FName), String(FName), IsDir and (not IsLnk), JobType = WORKER_JOB_MOVE);
+ HandleProcessPattern(List, InaccessiblePaths, CurrPath, CurrPath + String(FName), String(FName), IsDir and (not IsLnk), JobType = WORKER_JOB_MOVE);
end else begin // Extract from VFS mode
DebugMsg(['CopyFilesWorker: Should not be reached']);
if (not ExtractFromVFSAll) and Assigned(SelectedItem)
- then HandleProcessPattern(List, CurrPath, CurrPath + String(SelectedItem^.FName), String(SelectedItem^.FName), SelectedItem^.IsDir and (not SelectedItem^.IsLnk), JobType = WORKER_JOB_MOVE)
+ then HandleProcessPattern(List, InaccessiblePaths, CurrPath, CurrPath + String(SelectedItem^.FName), String(SelectedItem^.FName), SelectedItem^.IsDir and (not SelectedItem^.IsLnk), JobType = WORKER_JOB_MOVE)
else begin
SaveSrcPath := IncludeTrailingPathDelimiter(SrcEngine.Path);
SrcEngine.SetPath('/');
CurrPath := '/';
- HandleProcessPattern(List, '/', '/', '', True, False);
+ HandleProcessPattern(List, InaccessiblePaths, '/', '/', '', True, False);
end;
end;
end;
@@ -1457,79 +1486,85 @@ begin
if SrcEngine.ChangeDir(CurrPath) <> 0 then DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour may occur.']); }
DebugWriteListSL(List);
- __chdir('/');
- // Compute total size of files to copy
- FTotalSize := 0;
- FTotalDone := 0;
- if List.Count > 0 then
- for i := 0 to List.Count - 1 do
- if PDataItemSL(List[i])^.Stage1 and (PDataItemSL(List[i])^.DataItem^.Size > 0) and (not PDataItemSL(List[i])^.DataItem^.IsDir) and (not PDataItemSL(List[i])^.DataItem^.IsLnk)
- then Inc(FTotalSize, PDataItemSL(List[i])^.DataItem^.Size);
- SrcEngine.BlockSize := ComputeBlockSize(FTotalSize);
- DestEngine.BlockSize := ComputeBlockSize(FTotalSize);
-
- // Prepare the Progress window
- SetProgress2Params(FTotalSize + Ord(FTotalSize = 0));
- UpdateProgress1(0, '0%');
- UpdateProgress2(0, '0%');
- CommitGUIUpdate;
-
- DefResponse := 0;
- SkipAll := False;
- FCopySkipAllErrors := False;
+ SkipInaccessible := False;
+ if InaccessiblePaths.Count > 0 then
+ SkipInaccessible := ShowInaccessibleDialog(InaccessiblePaths) <> 1;
+
+ if not SkipInaccessible then begin
+ __chdir('/');
+ // Compute total size of files to copy
+ FTotalSize := 0;
+ FTotalDone := 0;
+ if List.Count > 0 then
+ for i := 0 to List.Count - 1 do
+ if PDataItemSL(List[i])^.Stage1 and (PDataItemSL(List[i])^.DataItem^.Size > 0) and (not PDataItemSL(List[i])^.DataItem^.IsDir) and (not PDataItemSL(List[i])^.DataItem^.IsLnk)
+ then Inc(FTotalSize, PDataItemSL(List[i])^.DataItem^.Size);
+ SrcEngine.BlockSize := ComputeBlockSize(FTotalSize);
+ DestEngine.BlockSize := ComputeBlockSize(FTotalSize);
+
+ // Prepare the Progress window
+ SetProgress2Params(FTotalSize + Ord(FTotalSize = 0));
+ UpdateProgress1(0, '0%');
+ UpdateProgress2(0, '0%');
+ CommitGUIUpdate;
- if List.Count > 0 then begin
- StartPassed := True;
- if SrcEngine is TVFSEngine then
- StartPassed := StartPassed and (SrcEngine as TVFSEngine).StartCopyOperation(@vfs_ask_question_callback, @vfs_ask_password_callback, @vfs_copy_progress_callback, Self);
- if DestEngine is TVFSEngine then
- StartPassed := StartPassed and (DestEngine as TVFSEngine).StartCopyOperation(@vfs_ask_question_callback, @vfs_ask_password_callback, @vfs_copy_progress_callback, Self);
-
- if StartPassed then
- for i := 0 to List.Count - 1 do begin
- if Assigned(PDataItemSL(List[i])^.ADestination)
- then s := string(PDataItemSL(List[i])^.ADestination)
- else
- begin
- s := ProcessPattern(DestEngine, CopyTargetPath, CurrPath, Copy(PDataItemSL(List[i])^.DataItem^.FName, Length(CurrPath) + 1, Length(PDataItemSL(List[i])^.DataItem^.FName) - Length(CurrPath)),
- PDataItemSL(List[i])^.DataItem^.IsDir and (not PDataItemSL(List[i])^.DataItem^.IsLnk));
-// DebugMsg(['s2 = ', Copy(PDataItemSL(List[i])^.AName, Length(CurrPath) + 1, Length(PDataItemSL(List[i])^.AName) - Length(CurrPath)), ', s = ', s]);
- end;
+ DefResponse := 0;
+ SkipAll := False;
+ FCopySkipAllErrors := False;
+
+ if List.Count > 0 then begin
+ StartPassed := True;
+ if SrcEngine is TVFSEngine then
+ StartPassed := StartPassed and (SrcEngine as TVFSEngine).StartCopyOperation(@vfs_ask_question_callback, @vfs_ask_password_callback, @vfs_copy_progress_callback, Self);
+ if DestEngine is TVFSEngine then
+ StartPassed := StartPassed and (DestEngine as TVFSEngine).StartCopyOperation(@vfs_ask_question_callback, @vfs_ask_password_callback, @vfs_copy_progress_callback, Self);
+
+ if StartPassed then
+ for i := 0 to List.Count - 1 do begin
+ if Assigned(PDataItemSL(List[i])^.ADestination)
+ then s := string(PDataItemSL(List[i])^.ADestination)
+ else
+ begin
+ s := ProcessPattern(DestEngine, CopyTargetPath, CurrPath, Copy(PDataItemSL(List[i])^.DataItem^.FName, Length(CurrPath) + 1, Length(PDataItemSL(List[i])^.DataItem^.FName) - Length(CurrPath)),
+ PDataItemSL(List[i])^.DataItem^.IsDir and (not PDataItemSL(List[i])^.DataItem^.IsLnk));
+// DebugMsg(['s2 = ', Copy(PDataItemSL(List[i])^.AName, Length(CurrPath) + 1, Length(PDataItemSL(List[i])^.AName) - Length(CurrPath)), ', s = ', s]);
+ end;
- if not (SrcEngine is TVFSEngine) then UpdateCaption1(Format(LANGFromS, [string(PDataItemSL(List[i])^.DataItem^.FDisplayName)])) else
- if (SrcEngine as TVFSEngine).ArchiveMode then UpdateCaption1(Format(LANGFromS, [Format(ConstFullPathFormatStr, [(SrcEngine as TVFSEngine).ArchivePath, string(PDataItemSL(List[i])^.DataItem^.FDisplayName)])]))
- else UpdateCaption1(Format(LANGFromS, [GetURIPrefix((SrcEngine as TVFSEngine).GetPathURI) + StrToUTF8(string(PDataItemSL(List[i])^.DataItem^.FDisplayName))]));
- if not (DestEngine is TVFSEngine) then UpdateCaption2(Format(LANGToS, [StrToUTF8(s)])) else
- if (DestEngine as TVFSEngine).ArchiveMode then UpdateCaption2(Format(LANGToS, [Format(ConstFullPathFormatStr, [(DestEngine as TVFSEngine).ArchivePath, StrToUTF8(s)])]))
- else UpdateCaption2(Format(LANGToS, [GetURIPrefix((DestEngine as TVFSEngine).GetPathURI) + StrToUTF8(s)]));
- CommitGUIUpdate;
- if TwoSameFiles(s, string(PDataItemSL(List[i])^.DataItem^.FName), (JobType in [WORKER_JOB_COPY, WORKER_JOB_EXTRACT_TO_TEMP])) and (not PDataItemSL(List[i])^.DataItem^.IsDir) then begin
- FCancelMessage := LANGCannotCopyFileToItself;
- FShowCancelMessage := True;
- ErrorHappened := True;
- Break;
- end;
+ if not (SrcEngine is TVFSEngine) then UpdateCaption1(Format(LANGFromS, [string(PDataItemSL(List[i])^.DataItem^.FDisplayName)])) else
+ if (SrcEngine as TVFSEngine).ArchiveMode then UpdateCaption1(Format(LANGFromS, [Format(ConstFullPathFormatStr, [(SrcEngine as TVFSEngine).ArchivePath, string(PDataItemSL(List[i])^.DataItem^.FDisplayName)])]))
+ else UpdateCaption1(Format(LANGFromS, [GetURIPrefix((SrcEngine as TVFSEngine).GetPathURI) + StrToUTF8(string(PDataItemSL(List[i])^.DataItem^.FDisplayName))]));
+ if not (DestEngine is TVFSEngine) then UpdateCaption2(Format(LANGToS, [StrToUTF8(s)])) else
+ if (DestEngine as TVFSEngine).ArchiveMode then UpdateCaption2(Format(LANGToS, [Format(ConstFullPathFormatStr, [(DestEngine as TVFSEngine).ArchivePath, StrToUTF8(s)])]))
+ else UpdateCaption2(Format(LANGToS, [GetURIPrefix((DestEngine as TVFSEngine).GetPathURI) + StrToUTF8(s)]));
+ CommitGUIUpdate;
+ if TwoSameFiles(s, string(PDataItemSL(List[i])^.DataItem^.FName), (JobType in [WORKER_JOB_COPY, WORKER_JOB_EXTRACT_TO_TEMP])) and (not PDataItemSL(List[i])^.DataItem^.IsDir) then begin
+ FCancelMessage := LANGCannotCopyFileToItself;
+ FShowCancelMessage := True;
+ ErrorHappened := True;
+ Break;
+ end;
// * FIXME: why the hell we had something like this here??
-// if s <> string(PDataItemSL(List[i])^.DataItem^.FName) then
- if not HandleCopy(List[i], s) then begin
+// if s <> string(PDataItemSL(List[i])^.DataItem^.FName) then
+ if not HandleCopy(List[i], s) then begin
+ ErrorHappened := True;
+ Break;
+ end;
+ if (not PDataItemSL(List[i])^.DataItem^.IsDir) and (not PDataItemSL(List[i])^.DataItem^.IsLnk)
+ then Inc(FTotalDone, PDataItemSL(List[i])^.DataItem^.Size);
+ if FCancelled then begin
+ FCancelMessage := LANGUserCancelled;
+ FShowCancelMessage := True;
ErrorHappened := True;
Break;
end;
- if (not PDataItemSL(List[i])^.DataItem^.IsDir) and (not PDataItemSL(List[i])^.DataItem^.IsLnk)
- then Inc(FTotalDone, PDataItemSL(List[i])^.DataItem^.Size);
- if FCancelled then begin
- FCancelMessage := LANGUserCancelled;
- FShowCancelMessage := True;
- ErrorHappened := True;
- Break;
end;
- end;
- // We need to ensure these to be called in case of error
- if SrcEngine is TVFSEngine then
- (SrcEngine as TVFSEngine).StopCopyOperation(@vfs_copy_progress_callback, Self);
- if DestEngine is TVFSEngine then
- (DestEngine as TVFSEngine).StopCopyOperation(@vfs_copy_progress_callback, Self);
+ // We need to ensure these to be called in case of error
+ if SrcEngine is TVFSEngine then
+ (SrcEngine as TVFSEngine).StopCopyOperation(@vfs_copy_progress_callback, Self);
+ if DestEngine is TVFSEngine then
+ (DestEngine as TVFSEngine).StopCopyOperation(@vfs_copy_progress_callback, Self);
+ end;
end;
// Free the objects
@@ -1537,6 +1572,7 @@ begin
for i := List.Count - 1 downto 0 do FreeDataItem(PDataItemSL(List[i]));
List.Clear;
List.Free;
+ InaccessiblePaths.Free;
// * TODO: check error
if not DestEngine.ChangeDir(SaveDestPath, nil) then
DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour might occur.']);
@@ -1992,38 +2028,48 @@ var SkipAll: boolean;
var i: longint;
AList: TList;
+ InaccessiblePaths: TStringList;
Fr: Single;
+ SkipInaccessible: boolean;
begin
SkipAll := False;
AList := TList.Create;
- PrepareJobFilesFromPanel(AList, ChmodRecurseType < 0);
- libc_chdir('/');
- SetProgress1Params(AList.Count);
- UpdateProgress1(0, '0 %');
- CommitGUIUpdate;
+ InaccessiblePaths := TStringList.Create;
+ PrepareJobFilesFromPanel(AList, InaccessiblePaths, ChmodRecurseType < 0);
-// DebugWriteListSL(AList);
+ SkipInaccessible := False;
+ if InaccessiblePaths.Count > 0 then
+ SkipInaccessible := ShowInaccessibleDialog(InaccessiblePaths) <> 1;
- if AList.Count = 1 then Fr := 1 else Fr := 100 / (AList.Count - 1);
- if AList.Count > 0 then
- for i := 0 to AList.Count - 1 do begin
- if FCancelled then begin
- FCancelMessage := LANGUserCancelled;
- FShowCancelMessage := True;
- Break;
- end;
- // Process chmod
- if not HandleChmod(AList[i]) then Break;
- UpdateProgress1(i, Format('%d%%', [Round(Fr * i)]));
- UpdateCaption1(PDataItemSL(AList[i])^.DataItem^.FDisplayName);
- CommitGUIUpdate;
- end;
+ if not SkipInaccessible then begin
+ libc_chdir('/');
+ SetProgress1Params(AList.Count);
+ UpdateProgress1(0, '0 %');
+ CommitGUIUpdate;
+
+// DebugWriteListSL(AList);
+ if AList.Count = 1 then Fr := 1 else Fr := 100 / (AList.Count - 1);
+ if AList.Count > 0 then
+ for i := 0 to AList.Count - 1 do begin
+ if FCancelled then begin
+ FCancelMessage := LANGUserCancelled;
+ FShowCancelMessage := True;
+ Break;
+ end;
+ // Process chmod
+ if not HandleChmod(AList[i]) then Break;
+ UpdateProgress1(i, Format('%d%%', [Round(Fr * i)]));
+ UpdateCaption1(PDataItemSL(AList[i])^.DataItem^.FDisplayName);
+ CommitGUIUpdate;
+ end;
+ end;
// Free the objects
if AList.Count > 0 then
for i := AList.Count - 1 downto 0 do FreeDataItem(PDataItemSL(AList[i]));
AList.Clear;
AList.Free;
+ InaccessiblePaths.Free;
end;
@@ -2068,38 +2114,48 @@ var SkipAll: boolean;
var i: longint;
AList: TList;
+ InaccessiblePaths: TStringList;
Fr: Single;
+ SkipInaccessible: boolean;
begin
SkipAll := False;
AList := TList.Create;
- PrepareJobFilesFromPanel(AList, not ChownRecursive);
- libc_chdir('/');
- SetProgress1Params(AList.Count);
- UpdateProgress1(0, '0 %');
- CommitGUIUpdate;
+ InaccessiblePaths := TStringList.Create;
+ PrepareJobFilesFromPanel(AList, InaccessiblePaths, not ChownRecursive);
-// DebugWriteListSL(AList);
+ SkipInaccessible := False;
+ if InaccessiblePaths.Count > 0 then
+ SkipInaccessible := ShowInaccessibleDialog(InaccessiblePaths) <> 1;
- if AList.Count = 1 then Fr := 1 else Fr := 100 / (AList.Count - 1);
- if AList.Count > 0 then
- for i := 0 to AList.Count - 1 do begin
- if FCancelled then begin
- FCancelMessage := LANGUserCancelled;
- FShowCancelMessage := True;
- Break;
- end;
- // Process chmod
- if not HandleChown(AList[i]) then Break;
- UpdateProgress1(i, Format('%d%%', [Round(Fr * i)]));
- UpdateCaption1(PDataItemSL(AList[i])^.DataItem^.FDisplayName);
- CommitGUIUpdate;
- end;
+ if not SkipInaccessible then begin
+ libc_chdir('/');
+ SetProgress1Params(AList.Count);
+ UpdateProgress1(0, '0 %');
+ CommitGUIUpdate;
+
+// DebugWriteListSL(AList);
+ if AList.Count = 1 then Fr := 1 else Fr := 100 / (AList.Count - 1);
+ if AList.Count > 0 then
+ for i := 0 to AList.Count - 1 do begin
+ if FCancelled then begin
+ FCancelMessage := LANGUserCancelled;
+ FShowCancelMessage := True;
+ Break;
+ end;
+ // Process chmod
+ if not HandleChown(AList[i]) then Break;
+ UpdateProgress1(i, Format('%d%%', [Round(Fr * i)]));
+ UpdateCaption1(PDataItemSL(AList[i])^.DataItem^.FDisplayName);
+ CommitGUIUpdate;
+ end;
+ end;
// Free the objects
if AList.Count > 0 then
for i := AList.Count - 1 downto 0 do FreeDataItem(PDataItemSL(AList[i]));
AList.Clear;
AList.Free;
+ InaccessiblePaths.Free;
end;
diff --git a/UGnome.pas b/UGnome.pas
index 9fa0319..7871f3e 100644
--- a/UGnome.pas
+++ b/UGnome.pas
@@ -165,6 +165,8 @@ function HandleVFSAskPasswordCallback(DialogParent: PGtkWidget;
domain: PPChar;
password_save: PVFSPasswordSave): gboolean;
+function ShowInaccessiblePathsDialog(DialogParent: PGtkWidget; List: TStringList): integer;
+
type PGnomeColorPicker = PGtkWidget;
@@ -1551,6 +1553,65 @@ end;
(********************************************************************************************************************************)
(********************************************************************************************************************************)
+function ShowInaccessiblePathsDialog(DialogParent: PGtkWidget; List: TStringList): integer;
+var dialog: PGtkWidget;
+ hbox, vbox, expander: PGtkWidget;
+ primary_label, secondary_label, details_label, image: PGtkWidget;
+ scrolled_window: PGtkWidget;
+begin
+ if not Assigned(List) or (List.Count = 0) then Exit;
+ dialog := gtk_dialog_new;
+ if DialogParent <> nil then gtk_window_set_transient_for(PGtkWindow(dialog), PGtkWindow(DialogParent));
+ gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
+ gtk_box_set_spacing(GTK_BOX(PGtkDialog(dialog)^.vbox), 14);
+ gtk_window_set_resizable(GTK_WINDOW (dialog), False);
+ gtk_dialog_set_has_separator(PGtkDialog(dialog), False);
+ gtk_window_set_title(GTK_WINDOW(dialog), '');
+ gtk_window_set_skip_taskbar_hint(GTK_WINDOW(dialog), True);
+
+ primary_label := gtk_label_new(nil);
+ gtk_label_set_markup(PGtkLabel(primary_label), PChar(Format('<span size="large" weight="ultrabold">%s</span>', ['Inaccessible folders and files'])));
+ secondary_label := gtk_label_new('Some files are not accessible and will be skipped. Press Cancel to abort the operation or Continue to ignore this warning.');
+ details_label := gtk_label_new(nil);
+ gtk_label_set_label(PGtkLabel(details_label), PChar(List.Text));
+ image := gtk_image_new_from_stock(GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG);
+ gtk_misc_set_alignment(GTK_MISC(image), 0.5, 0.0);
+ gtk_label_set_line_wrap(GTK_LABEL(primary_label), True);
+ gtk_label_set_selectable(GTK_LABEL(primary_label), True);
+ gtk_misc_set_alignment(GTK_MISC(primary_label), 0.0, 0.5);
+ gtk_label_set_line_wrap(GTK_LABEL(secondary_label), True);
+ gtk_label_set_selectable(GTK_LABEL(secondary_label), True);
+ gtk_misc_set_alignment(GTK_MISC(secondary_label), 0.0, 0.5);
+ gtk_label_set_line_wrap(GTK_LABEL(details_label), False);
+ gtk_label_set_selectable(GTK_LABEL(details_label), True);
+ gtk_misc_set_alignment(GTK_MISC(details_label), 0.0, 0.5);
+ scrolled_window := gtk_scrolled_window_new(nil, nil);
+ gtk_scrolled_window_set_policy(PGtkScrolledWindow(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_add_with_viewport(PGtkScrolledWindow(scrolled_window), details_label);
+ hbox := gtk_hbox_new (False, 12);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
+ gtk_box_pack_start(GTK_BOX(hbox), image, False, False, 0);
+ vbox := gtk_vbox_new(False, 12);
+ gtk_box_pack_start(GTK_BOX(hbox), vbox, False, False, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), primary_label, False, False, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), secondary_label, False, False, 0);
+ expander := gtk_expander_new_with_mnemonic('Show more _details');
+ gtk_expander_set_spacing(GTK_EXPANDER(expander), 6);
+ gtk_container_add(GTK_CONTAINER(expander), scrolled_window);
+ gtk_box_pack_start(GTK_BOX(vbox), expander, False, False, 0);
+ gtk_box_pack_start(GTK_BOX(PGtkDialog(dialog)^.vbox), hbox, False, False, 0);
+
+ gtk_dialog_add_button(PGtkDialog(dialog), GTK_STOCK_CANCEL, 0);
+ gtk_dialog_add_button(PGtkDialog(dialog), 'C_ontinue', 1);
+ gtk_dialog_set_default_response(PGtkDialog(dialog), 1);
+ gtk_widget_show_all(dialog);
+
+ Result := gtk_dialog_run(PGtkDialog(dialog));
+ gtk_widget_destroy(Dialog);
+end;
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
(********************************************************************************************************************************)
(********************************************************************************************************************************)
(********************************************************************************************************************************)