diff options
| author | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2010-02-14 15:12:08 +0100 |
|---|---|---|
| committer | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2010-02-14 15:12:08 +0100 |
| commit | d338f1f0c1a72665396d95bfe303ed408a3f10b9 (patch) | |
| tree | c41c71b380e1b749a49518a57edd3453a3733a5f | |
| parent | 55605a80092452ce593cb05df12a404ad47aa808 (diff) | |
| download | tuxcmd-0.6.76.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.pas | 4 | ||||
| -rw-r--r-- | UCore.pas | 9 | ||||
| -rw-r--r-- | UCoreUtils.pas | 2 | ||||
| -rw-r--r-- | UCoreWorkers.pas | 298 | ||||
| -rw-r--r-- | UGnome.pas | 61 |
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} @@ -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; @@ -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; + +(********************************************************************************************************************************) +(********************************************************************************************************************************) (********************************************************************************************************************************) (********************************************************************************************************************************) (********************************************************************************************************************************) |
