Переглянути джерело

Merge branch 'overwriteall' into main

# Conflicts:
#	whatsnew.htm

Will probably do the same thing for 'promptifolder' later.

Updated copyright dates & .isl version numbers during merge.
Martijn Laan 5 роки тому
батько
коміт
ffaf1d2bcd

+ 6 - 1
Files/Default.isl

@@ -1,4 +1,4 @@
-; *** Inno Setup version 6.0.3+ English messages ***
+; *** Inno Setup version 6.0.6+ English messages ***
 ;
 ; To download user-contributed translations of this file, go to:
 ;   https://jrsoftware.org/files/istrans/
@@ -292,7 +292,12 @@ ExistingFileReadOnly2=The existing file could not be replaced because it is mark
 ExistingFileReadOnlyRetry=&Remove the read-only attribute and try again
 ExistingFileReadOnlyKeepExisting=&Keep the existing file
 ErrorReadingExistingDest=An error occurred while trying to read the existing file:
+FileExistsSelectAction=Select action
 FileExists=The file already exists.%n%nWould you like Setup to overwrite it?
+FileExists2=The file already exists.
+FileExistsOverwriteExisting=&Overwrite the existing file
+FileExistsKeepExisting=&Keep the existing file
+FileExistsOverwriteOrKeepAll=&Do this for the next conflicts
 ExistingFileNewer=The existing file is newer than the one Setup is trying to install. It is recommended that you keep the existing file.%n%nDo you want to keep the existing file?
 ErrorChangingAttr=An error occurred while trying to change the attributes of the existing file:
 ErrorCreatingTemp=An error occurred while trying to create a file in the destination directory:

+ 6 - 1
Files/Languages/Dutch.isl

@@ -1,4 +1,4 @@
-; *** Inno Setup version 6.0.3+ Dutch messages ***
+; *** Inno Setup version 6.0.6+ Dutch messages ***
 ;
 ; This file is based on user-contributed translations by various authors
 ;
@@ -272,7 +272,12 @@ ExistingFileReadOnly2=Het bestaande bestand kon niet vervangen worden omdat het
 ExistingFileReadOnlyRetry=&Verwijder de alleen-lezen markering en probeer het opnieuw
 ExistingFileReadOnlyKeepExisting=&Behoud het bestaande bestand
 ErrorReadingExistingDest=Er is een fout opgetreden bij het lezen van het bestaande bestand:
+FileExistsSelectAction=Selecteer actie
 FileExists=Het bestand bestaat al.%n%nWilt u dat Setup het overschrijft?
+FileExists2=Het bestand bestaat al.
+FileExistsOverwriteExisting=&Overschrijf het bestaande bestand
+FileExistsKeepExisting=&Behoud het bestaande bestand
+FileExistsOverwriteOrKeepAll=&Dit voor de volgende conflicten uitvoeren
 ExistingFileNewer=Het bestaande bestand is nieuwer dan het bestand dat Setup probeert te installeren. U wordt aanbevolen het bestaande bestand te behouden.%n%nWilt u het bestaande bestand behouden?
 ErrorChangingAttr=Er is een fout opgetreden bij het wijzigen van de kenmerken van het bestaande bestand:
 ErrorCreatingTemp=Er is een fout opgetreden bij het maken van een bestand in de doelmap:

+ 4 - 2
Projects/Compile.pas

@@ -7363,6 +7363,9 @@ procedure TSetupCompiler.ReadMessagesFromScript;
     ReadMessagesFromFiles('compiler:Default.isl', LanguageEntries.Count-1);
   end;
 
+const
+  OptionalMessages: set of TSetupMessageID = [msgComponentsDiskSpaceGBLabel, msgDiskSpaceGBLabel, msgPrepareToInstallNeedsRestart,
+    msgFileExistsSelectAction, msgFileExists2, msgFileExistsOverwriteExisting, msgFileExistsKeepExisting, msgFileExistsOverwriteOrKeepAll];
 var
   I: Integer;
   LangData: TLangData;
@@ -7388,8 +7391,7 @@ begin
   for I := 0 to LanguageEntries.Count-1 do begin
     LangData := LangDataList[I];
     for J := Low(LangData.Messages) to High(LangData.Messages) do
-      if not LangData.MessagesDefined[J] and
-         not (J in [msgComponentsDiskSpaceGBLabel, msgDiskSpaceGBLabel, msgPrepareToInstallNeedsRestart]) then begin
+      if not LangData.MessagesDefined[J] and not (J in OptionalMessages) then begin
         { Use the message from Default.isl }
         if not (J in [msgHelpTextNote, msgTranslatorNote]) then
           WarningsList.Add(Format(SCompilerMessagesMissingMessageWarning,

+ 58 - 22
Projects/Install.pas

@@ -897,9 +897,13 @@ var
     F.WriteBuffer(UninstallerMsgTail, SizeOf(UninstallerMsgTail));
   end;
 
+  type
+    TYesOrNoToAll = (ynNone, ynYes, ynNo);
+
   procedure ProcessFileEntry(const CurFile: PSetupFileEntry;
     const DisableFsRedir: Boolean; ASourceFile, ADestName: String;
-    const FileLocationFilenames: TStringList; const AExternalSize: Integer64);
+    const FileLocationFilenames: TStringList; const AExternalSize: Integer64;
+    var ConfirmOverwriteAll: TYesOrNoToAll);
 
     procedure InstallFont(const Filename, FontName: String;
       const AddToFontTableNow: Boolean);
@@ -1057,6 +1061,8 @@ var
     LastError: DWORD;
     DestF, SourceF: TFile;
     Flags: TMakeDirFlags;
+    VerificationFlagChecked: BOOL;
+    Overwrite: Boolean;
   label Retry, Skip;
   begin
     Log('-- File entry --');
@@ -1203,10 +1209,15 @@ var
                  ((ExistingVersionInfo.MS > CurFileVersionInfo.MS) or
                   ((ExistingVersionInfo.MS = CurFileVersionInfo.MS) and
                    (ExistingVersionInfo.LS > CurFileVersionInfo.LS))) then begin
-                if not(foPromptIfOlder in CurFile^.Options) or
-                   IsProtectedFile or
-                   (LoggedMsgBox(DestFile + SNewLine2 + SetupMessages[msgExistingFileNewer],
-                    '', mbError, MB_YESNO, True, IDYES) <> IDNO) then begin
+                { Existing file is newer, ask user what to do unless we shouldn't }
+                if (foPromptIfOlder in CurFile^.Options) and not IsProtectedFile then begin
+                  Overwrite := LoggedMsgBox(DestFile + SNewLine2 + SetupMessages[msgExistingFileNewer],
+                      '', mbError, MB_YESNO, True, IDYES) = IDNO;
+                  if not Overwrite then begin
+                    Log('User opted not to overwrite the existing file. Skipping.');
+                    goto Skip;
+                  end;
+                end else begin
                   Log('Existing file is a newer version. Skipping.');
                   goto Skip;
                 end;
@@ -1280,11 +1291,15 @@ var
               goto Skip;
             end;
             if CompareFileTime(ExistingFileDate, CurFileDate) > 0 then begin
-              { Existing file has a later time stamp }
-              if not(foPromptIfOlder in CurFile^.Options) or
-                 IsProtectedFile or
-                 (LoggedMsgBox(DestFile + SNewLine2 + SetupMessages[msgExistingFileNewer],
-                  '', mbError, MB_YESNO, True, IDYES) <> IDNO) then begin
+              { Existing file has a later time stamp, ask user what to do unless we shouldn't }
+              if (foPromptIfOlder in CurFile^.Options) and not IsProtectedFile then begin
+                Overwrite := LoggedMsgBox(DestFile + SNewLine2 + SetupMessages[msgExistingFileNewer],
+                    '', mbError, MB_YESNO, True, IDYES) = IDNO;
+                if not Overwrite then begin
+                  Log('User opted not to overwrite the existing file. Skipping.');
+                  goto Skip;
+                end;
+              end else begin
                 Log('Existing file has a later time stamp. Skipping.');
                 goto Skip;
               end;
@@ -1301,13 +1316,31 @@ var
             goto Skip;
           end;
 
-          { If file already exists and foConfirmOverwrite is in Options, ask
-            the user if it's OK to overwrite }
-          if (foConfirmOverwrite in CurFile^.Options) and
-             (LoggedMsgBox(DestFile + SNewLine2 + SetupMessages[msgFileExists],
-              '', mbConfirmation, MB_YESNO, True, IDNO) <> IDYES) then begin
-            Log('User opted not to overwrite the existing file. Skipping.');
-            goto Skip;
+          { If file already exists and foConfirmOverwrite is in Options and the user didn't already
+            say it's OK to overwrite all, ask the user if it's OK to overwrite unless the user
+            already said to keep (=not overwrite) all }
+          if (foConfirmOverwrite in CurFile^.Options) and not(ConfirmOverwriteAll = ynYes) then begin
+            if not(ConfirmOverwriteAll = ynNo) then begin
+              if SetupMessages[msgFileExists2] = '' then begin
+                Overwrite := LoggedMsgBox(DestFile + SNewLine2 + SetupMessages[msgFileExists], '',
+                  mbConfirmation, MB_YESNO, True, IDNO) = IDYES;
+                VerificationFlagChecked := False;
+              end else
+                Overwrite := LoggedTaskDialogMsgBox('', SetupMessages[msgFileExistsSelectAction],
+                  DestFile + SNewLine2 + SetupMessages[msgFileExists2], '', mbConfirmation, MB_YESNO,
+                  [SetupMessages[msgFileExistsOverwriteExisting], SetupMessages[msgFileExistsKeepExisting]],
+                  0, True, IDNO, SetupMessages[msgFileExistsOverwriteOrKeepAll], @VerificationFlagChecked) = IDYES;
+              if VerificationFlagChecked then begin
+                if Overwrite then
+                  ConfirmOverwriteAll := ynYes
+                else
+                  ConfirmOverwriteAll := ynNo;
+              end;
+            end;
+            if (ConfirmOverwriteAll = ynNo) or not Overwrite then begin
+              Log('User opted not to overwrite the existing file. Skipping.');
+              goto Skip;
+            end;
           end;
 
           { Check if existing file is read-only }
@@ -1683,7 +1716,7 @@ var
     function RecurseExternalCopyFiles(const DisableFsRedir: Boolean;
       const SearchBaseDir, SearchSubDir, SearchWildcard: String; const SourceIsWildcard: Boolean;
       const CurFile: PSetupFileEntry; const FileLocationFilenames: TStringList;
-      var ExpectedBytesLeft: Integer64): Boolean;
+      var ExpectedBytesLeft: Integer64; var ConfirmOverwriteAll: TYesOrNoToAll): Boolean;
     var
       SearchFullPath, FileName, SourceFile, DestName: String;
       H: THandle;
@@ -1723,7 +1756,7 @@ var
                 Size := ExpectedBytesLeft;
               end;
               ProcessFileEntry(CurFile, DisableFsRedir, SourceFile, DestName,
-                FileLocationFilenames, Size);
+                FileLocationFilenames, Size, ConfirmOverwriteAll);
               Dec6464(ExpectedBytesLeft, Size);
             end;
           until not FindNextFile(H, FindData);
@@ -1741,7 +1774,7 @@ var
                 Result := RecurseExternalCopyFiles(DisableFsRedir, SearchBaseDir,
                   SearchSubDir + FindData.cFileName + '\', SearchWildcard,
                   SourceIsWildcard, CurFile, FileLocationFileNames,
-                  ExpectedBytesLeft) or Result;
+                  ExpectedBytesLeft, ConfirmOverwriteAll) or Result;
             until not FindNextFile(H, FindData);
           finally
             Windows.FindClose(H);
@@ -1781,7 +1814,10 @@ var
     SourceWildcard: String;
     ProgressBefore, ExpectedBytesLeft: Integer64;
     DisableFsRedir, FoundFiles: Boolean;
+    ConfirmOverwriteAll: TYesOrNoToAll;
   begin
+    ConfirmOverwriteAll := ynNone;
+
     FileLocationFilenames := TStringList.Create;
     try
       for I := 0 to Entries[seFileLocation].Count-1 do
@@ -1805,7 +1841,7 @@ var
           if CurFile^.LocationEntry <> -1 then begin
             ExternalSize.Hi := 0;  { not used... }
             ExternalSize.Lo := 0;
-            ProcessFileEntry(CurFile, DisableFsRedir, '', '', FileLocationFilenames, ExternalSize);
+            ProcessFileEntry(CurFile, DisableFsRedir, '', '', FileLocationFilenames, ExternalSize, ConfirmOverwriteAll);
           end
           else begin
             { File is an 'external' file }
@@ -1823,7 +1859,7 @@ var
               FoundFiles := RecurseExternalCopyFiles(DisableFsRedir,
                 PathExtractPath(SourceWildcard), '', PathExtractName(SourceWildcard),
                 IsWildcard(SourceWildcard), CurFile, FileLocationFileNames,
-                ExpectedBytesLeft);
+                ExpectedBytesLeft, ConfirmOverwriteAll);
             until FoundFiles or
                   (foSkipIfSourceDoesntExist in CurFile^.Options) or
                   AbortRetryIgnoreTaskDialogMsgBox(

+ 10 - 6
Projects/Main.pas

@@ -228,7 +228,8 @@ function LoggedMsgBox(const Text, Caption: String; const Typ: TMsgBoxType;
   const Buttons: Cardinal; const Suppressible: Boolean; const Default: Integer): Integer;
 function LoggedTaskDialogMsgBox(const Icon, Instruction, Text, Caption: String;
   const Typ: TMsgBoxType; const Buttons: Cardinal; const ButtonLabels: array of String;
-  const ShieldButton: Integer; const Suppressible: Boolean; const Default: Integer): Integer;
+  const ShieldButton: Integer; const Suppressible: Boolean; const Default: Integer;
+  const VerificationText: String = ''; const pfVerificationFlagChecked: PBOOL = nil): Integer;
 procedure LogWindowsVersion;
 procedure NotifyAfterInstallEntry(const AfterInstall: String);
 procedure NotifyAfterInstallFileEntry(const FileEntry: PSetupFileEntry);
@@ -2429,7 +2430,8 @@ end;
 
 function LoggedTaskDialogMsgBox(const Icon, Instruction, Text, Caption: String;
   const Typ: TMsgBoxType; const Buttons: Cardinal; const ButtonLabels: array of String;
-  const ShieldButton: Integer; const Suppressible: Boolean; const Default: Integer): Integer;
+  const ShieldButton: Integer; const Suppressible: Boolean; const Default: Integer;
+  const VerificationText: String = ''; const pfVerificationFlagChecked: PBOOL = nil): Integer;
 begin
   if InitSuppressMsgBoxes and Suppressible then begin
     LogSuppressedMessageBox(PChar(Text), Buttons, Default);
@@ -2437,10 +2439,12 @@ begin
   end else begin
     LogMessageBox(PChar(Text), Buttons);
     Result := TaskDialogMsgBox(Icon, Instruction, Text,
-      Caption, Typ, Buttons, ButtonLabels, ShieldButton);
-    if Result <> 0 then
-      LogFmt('User chose %s.', [GetMessageBoxResultText(Result)])
-    else
+      Caption, Typ, Buttons, ButtonLabels, ShieldButton, VerificationText, pfVerificationFlagChecked);
+    if Result <> 0 then begin
+      LogFmt('User chose %s.', [GetMessageBoxResultText(Result)]);
+      if pfVerificationFlagChecked <> nil then
+        LogFmt('User chose %s for the verification.', [SYesNo[pfVerificationFlagChecked^]]);
+    end else
       Log('TaskDialogMsgBox failed.');
   end;
 end;

+ 6 - 1
Projects/MsgIDs.pas

@@ -2,7 +2,7 @@ unit MsgIDs;
 
 {
   Inno Setup
-  Copyright (C) 1997-2012 Jordan Russell
+  Copyright (C) 1997-2020 Jordan Russell
   Portions by Martijn Laan
   For conditions of distribution and use, see LICENSE.TXT.
 
@@ -106,7 +106,12 @@ type
     msgExitSetupTitle,
     msgFileAbortRetryIgnoreSkipNotRecommended,
     msgFileAbortRetryIgnoreIgnoreNotRecommended,
+    msgFileExistsSelectAction,
     msgFileExists,
+    msgFileExists2,
+    msgFileExistsOverwriteExisting,
+    msgFileExistsKeepExisting,
+    msgFileExistsOverwriteOrKeepAll,
     msgFileNotInDir2,
     msgFinishedHeadingLabel,
     msgFinishedLabel,

+ 10 - 8
Projects/TaskDialog.pas

@@ -2,7 +2,7 @@ unit TaskDialog;
 
 {
   Inno Setup
-  Copyright (C) 1997-2018 Jordan Russell
+  Copyright (C) 1997-2020 Jordan Russell
   Portions by Martijn Laan
   For conditions of distribution and use, see LICENSE.TXT.
 
@@ -12,14 +12,14 @@ unit TaskDialog;
 interface
 
 uses
-  CmnFunc;
+  Windows, CmnFunc;
 
-function TaskDialogMsgBox(const Icon, Instruction, Text, Caption: String; const Typ: TMsgBoxType; const Buttons: Cardinal; const ButtonLabels: array of String; const ShieldButton: Integer): Integer;
+function TaskDialogMsgBox(const Icon, Instruction, Text, Caption: String; const Typ: TMsgBoxType; const Buttons: Cardinal; const ButtonLabels: array of String; const ShieldButton: Integer; const VerificationText: String = ''; const pfVerificationFlagChecked: PBOOL = nil): Integer;
 
 implementation
 
 uses
-  Windows, Classes, StrUtils, Math, Forms, Dialogs, SysUtils, Commctrl, CmnFunc2, InstFunc, PathFunc;
+  Classes, StrUtils, Math, Forms, Dialogs, SysUtils, Commctrl, CmnFunc2, InstFunc, PathFunc;
 
 var
   TaskDialogIndirectFunc: function(const pTaskConfig: TTaskDialogConfig;
@@ -33,7 +33,7 @@ begin
   Result := S_OK;
 end;
 
-function DoTaskDialog(const hWnd: HWND; const Instruction, Text, Caption, Icon: PWideChar; const CommonButtons: Cardinal; const ButtonLabels: array of String; const ButtonIDs: array of Integer; const ShieldButton: Integer; const RightToLeft: Boolean; const TriggerMessageBoxCallbackFuncFlags: LongInt; var ModalResult: Integer): Boolean;
+function DoTaskDialog(const hWnd: HWND; const Instruction, Text, Caption, Icon: PWideChar; const CommonButtons: Cardinal; const ButtonLabels: array of String; const ButtonIDs: array of Integer; const ShieldButton: Integer; const RightToLeft: Boolean; const TriggerMessageBoxCallbackFuncFlags: LongInt; var ModalResult: Integer; const VerificationText: PWideChar; const pfVerificationFlagChecked: PBOOL): Boolean;
 var
   Config: TTaskDialogConfig;
   NButtonLabelsAvailable: Integer;
@@ -62,6 +62,8 @@ begin
     Config.pszMainIcon := Icon;
     Config.pszMainInstruction := Instruction;
     Config.pszContent := Text;
+    if VerificationText <> '' then
+      Config.pszVerificationText := VerificationText;
     if ShieldButton <> 0 then begin
       Config.pfCallback := ShieldButtonCallback;
       Config.lpCallbackData := ShieldButton;
@@ -84,7 +86,7 @@ begin
       ActiveWindow := GetActiveWindow;
       WindowList := DisableTaskWindows(0);
       try
-        Result := TaskDialogIndirectFunc(Config, @ModalResult, nil, nil) = S_OK;
+        Result := TaskDialogIndirectFunc(Config, @ModalResult, nil, pfVerificationFlagChecked) = S_OK;
       finally
         EnableTaskWindows(WindowList);
         SetActiveWindow(ActiveWindow);
@@ -97,7 +99,7 @@ begin
     Result := False;
 end;
 
-function TaskDialogMsgBox(const Icon, Instruction, Text, Caption: String; const Typ: TMsgBoxType; const Buttons: Cardinal; const ButtonLabels: array of String; const ShieldButton: Integer): Integer;
+function TaskDialogMsgBox(const Icon, Instruction, Text, Caption: String; const Typ: TMsgBoxType; const Buttons: Cardinal; const ButtonLabels: array of String; const ShieldButton: Integer; const VerificationText: String = ''; const pfVerificationFlagChecked: PBOOL = nil): Integer;
 var
   IconP: PChar;
   TDCommonButtons: Cardinal;
@@ -167,7 +169,7 @@ begin
     InternalError('TaskDialogMsgBox: Invalid ButtonLabels');
   if not DoTaskDialog(Application.Handle, PChar(Instruction), PChar(Text),
            GetMessageBoxCaption(PChar(Caption), Typ), IconP, TDCommonButtons, ButtonLabels, ButtonIDs, ShieldButton,
-           GetMessageBoxRightToLeft, IfThen(Typ in [mbError, mbCriticalError], MB_ICONSTOP, 0), Result) then //note that MB_ICONEXCLAMATION (used by mbError) includes MB_ICONSTOP (used by mbCriticalError)
+           GetMessageBoxRightToLeft, IfThen(Typ in [mbError, mbCriticalError], MB_ICONSTOP, 0), Result, PChar(VerificationText), pfVerificationFlagChecked) then //note that MB_ICONEXCLAMATION (used by mbError) includes MB_ICONSTOP (used by mbCriticalError)
     Result := 0;
 end;
 

+ 5 - 0
whatsnew.htm

@@ -39,6 +39,11 @@ For conditions of distribution and use, see <a href="https://jrsoftware.org/file
   </ul>
   </li>
   <li>Inno Setup Preprocessor (ISPP) change: Added new <tt>PackVersionComponents</tt>, <tt>UnpackVersionComponents</tt>, and <tt>ParseVersionPacked</tt> support functions.</li>
+  <li>Some messages have been added in this version: (<a href="https://github.com/jrsoftware/issrc/commit/812a27664fbd767ad870c5c2456df9e4f43676d9#diff-cd0edf55eb9daa93e632d6d4d86a91d8">View differences in Default.isl</a>).
+  <ul>
+    <li>FileExistsSelectAction, FileExists2, FileExistsOverwriteExisting, FileExistsKeepExisting, FileExistsOverwriteOrKeepAll: If the FileExists2 message is set by a translation, Setup will instead use these messages instead of the FileExist message to show <a href="https://i.imgur.com/AnF6qo8.png">more user friendly prompts</a> to overwrite or keep existing files if the <tt>confirmoverwrite</tt> flag is set.</li>
+  </ul>
+  </li>
   <li>QuickStart Pack: Now registers the Inno Setup compiler path in the Inno Script Studio options so that it will find the Inno Setup compiler automatically. Required because Inno Script Studio doesn't officially support Inno Setup 6.</li> 
   <li>Minor tweaks.</li>
 </ul>