Selaa lähdekoodia

Function "Keep remote directory up to date" can be started in a new window

Source commit: 2cb0af9c9fd298daecd8df6096cd20536377e51f
Martin Prikryl 7 vuotta sitten
vanhempi
sitoutus
c16fd9a54b

+ 18 - 0
source/core/Common.cpp

@@ -781,6 +781,24 @@ UnicodeString __fastcall EscapePuttyCommandParam(UnicodeString Param)
   return Param;
 }
 //---------------------------------------------------------------------------
+UnicodeString __fastcall StringsToParams(TStrings * Strings)
+{
+  UnicodeString Result;
+
+  for (int Index = 0; Index < Strings->Count; Index++)
+  {
+    UnicodeString Name = Strings->Names[Index];
+    UnicodeString Value = Strings->ValueFromIndex[Index];
+    // Do not quote if it is all-numeric
+    if (IntToStr(StrToIntDef(Value, -1)) != Value)
+    {
+      Value = FORMAT(L"\"%s\"", (EscapeParam(Value)));
+    }
+    Result += FORMAT(L" %s=%s", (Name, Value));
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 UnicodeString __fastcall ExpandEnvironmentVariables(const UnicodeString & Str)
 {
   UnicodeString Buf;

+ 1 - 0
source/core/Common.h

@@ -84,6 +84,7 @@ UnicodeString __fastcall ExpandFileNameCommand(const UnicodeString Command,
 void __fastcall ReformatFileNameCommand(UnicodeString & Command);
 UnicodeString __fastcall EscapeParam(const UnicodeString & Param);
 UnicodeString __fastcall EscapePuttyCommandParam(UnicodeString Param);
+UnicodeString __fastcall StringsToParams(TStrings * Strings);
 UnicodeString __fastcall ExpandEnvironmentVariables(const UnicodeString & Str);
 bool __fastcall SamePaths(const UnicodeString & Path1, const UnicodeString & Path2);
 bool __fastcall IsPathToSameFile(const UnicodeString & Path1, const UnicodeString & Path2);

+ 37 - 23
source/core/CopyParam.cpp

@@ -822,33 +822,47 @@ void __fastcall TCopyParamType::Load(THierarchicalStorage * Storage)
   NewerOnly = Storage->ReadBool(L"NewerOnly", NewerOnly);
 }
 //---------------------------------------------------------------------------
-void __fastcall TCopyParamType::Save(THierarchicalStorage * Storage) const
-{
-  Storage->WriteBool(L"AddXToDirectories", AddXToDirectories);
-  Storage->WriteString(L"Masks", AsciiFileMask.Masks);
-  Storage->WriteInteger(L"FileNameCase", FileNameCase);
-  Storage->WriteBool(L"PreserveReadOnly", PreserveReadOnly);
-  Storage->WriteBool(L"PreserveTime", PreserveTime);
-  Storage->WriteBool(L"PreserveTimeDirs", PreserveTimeDirs);
-  Storage->WriteBool(L"PreserveRights", PreserveRights);
-  Storage->WriteBool(L"IgnorePermErrors", IgnorePermErrors);
-  Storage->WriteString(L"Text", Rights.Text);
-  Storage->WriteInteger(L"TransferMode", TransferMode);
-  Storage->WriteInteger(L"ResumeSupport", ResumeSupport);
-  Storage->WriteInt64(L"ResumeThreshold", ResumeThreshold);
-  Storage->WriteInteger(L"ReplaceInvalidChars", (unsigned int)InvalidCharsReplacement);
-  Storage->WriteString(L"LocalInvalidChars", LocalInvalidChars);
-  Storage->WriteBool(L"CalculateSize", CalculateSize);
-  Storage->WriteString(L"IncludeFileMask", IncludeFileMask.Masks);
+void __fastcall TCopyParamType::Save(THierarchicalStorage * Storage, const TCopyParamType * Defaults) const
+{
+  // Same as in TSessionData::DoSave
+  #define WRITE_DATA_EX(TYPE, NAME, PROPERTY, CONV) \
+    if ((Defaults != NULL) && (CONV(Defaults->PROPERTY) == CONV(PROPERTY))) \
+    { \
+      Storage->DeleteValue(NAME); \
+    } \
+    else \
+    { \
+      Storage->Write ## TYPE(NAME, CONV(PROPERTY)); \
+    }
+  #define WRITE_DATA_CONV(TYPE, NAME, PROPERTY) WRITE_DATA_EX(TYPE, NAME, PROPERTY, WRITE_DATA_CONV_FUNC)
+  #define WRITE_DATA(TYPE, PROPERTY) WRITE_DATA_EX(TYPE, TEXT(#PROPERTY), PROPERTY, )
+
+  WRITE_DATA(Bool, AddXToDirectories);
+  WRITE_DATA_EX(String, L"Masks", AsciiFileMask.Masks, );
+  WRITE_DATA(Integer, FileNameCase);
+  WRITE_DATA(Bool, PreserveReadOnly);
+  WRITE_DATA(Bool, PreserveTime);
+  WRITE_DATA(Bool, PreserveTimeDirs);
+  WRITE_DATA(Bool, PreserveRights);
+  WRITE_DATA(Bool, IgnorePermErrors);
+  WRITE_DATA_EX(String, L"Text", Rights.Text, );
+  WRITE_DATA(Integer, TransferMode);
+  WRITE_DATA(Integer, ResumeSupport);
+  WRITE_DATA(Int64, ResumeThreshold);
+  #define WRITE_DATA_CONV_FUNC(X) (unsigned int)(X)
+  WRITE_DATA_CONV(Integer, L"ReplaceInvalidChars", InvalidCharsReplacement);
+  WRITE_DATA(String, LocalInvalidChars);
+  WRITE_DATA(Bool, CalculateSize);
+  WRITE_DATA_EX(String, L"IncludeFileMask", IncludeFileMask.Masks, );
   Storage->DeleteValue(L"ExcludeFileMask"); // obsolete
   Storage->DeleteValue(L"NegativeExclude"); // obsolete
   DebugAssert(FTransferSkipList.get() == NULL);
   DebugAssert(FTransferResumeFile.IsEmpty());
-  Storage->WriteBool(L"ClearArchive", ClearArchive);
-  Storage->WriteBool(L"RemoveCtrlZ", RemoveCtrlZ);
-  Storage->WriteBool(L"RemoveBOM", RemoveBOM);
-  Storage->WriteInteger(L"CPSLimit", CPSLimit);
-  Storage->WriteBool(L"NewerOnly", NewerOnly);
+  WRITE_DATA(Bool, ClearArchive);
+  WRITE_DATA(Bool, RemoveCtrlZ);
+  WRITE_DATA(Bool, RemoveBOM);
+  WRITE_DATA(Integer, CPSLimit);
+  WRITE_DATA(Bool, NewerOnly);
 }
 //---------------------------------------------------------------------------
 #define C(Property) (Property == rhp.Property)

+ 1 - 1
source/core/CopyParam.h

@@ -100,7 +100,7 @@ public:
   bool __fastcall SkipTransfer(UnicodeString FileName, bool Directory) const;
 
   void __fastcall Load(THierarchicalStorage * Storage);
-  void __fastcall Save(THierarchicalStorage * Storage) const;
+  void __fastcall Save(THierarchicalStorage * Storage, const TCopyParamType * Defaults = NULL) const;
   UnicodeString __fastcall GetInfoStr(UnicodeString Separator, int Attrs) const;
   bool __fastcall AnyUsableCopyParam(int Attrs) const;
   UnicodeString __fastcall GenerateTransferCommandArgs(

+ 35 - 18
source/core/HierarchicalStorage.cpp

@@ -1334,6 +1334,8 @@ private:
 
   bool __fastcall AllowWrite();
   void __fastcall NotImplemented();
+  bool __fastcall AllowSection(const UnicodeString & Section);
+  UnicodeString __fastcall FormatKey(const UnicodeString & Section, const UnicodeString & Ident);
 };
 //---------------------------------------------------------------------------
 __fastcall TOptionsIniFile::TOptionsIniFile(TStrings * Options, TWriteMode WriteMode, const UnicodeString & RootKey) :
@@ -1373,22 +1375,42 @@ bool __fastcall TOptionsIniFile::AllowWrite()
   }
 }
 //---------------------------------------------------------------------------
-UnicodeString __fastcall TOptionsIniFile::ReadString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Default)
+bool __fastcall TOptionsIniFile::AllowSection(const UnicodeString & Section)
 {
   UnicodeString Name = Section;
   if (!Name.IsEmpty())
   {
     Name += PathDelim;
   }
+  bool Result = SameText(Name.SubString(1, FRootKey.Length()), FRootKey);
+  return Result;
+}
+//---------------------------------------------------------------------------
+UnicodeString __fastcall TOptionsIniFile::FormatKey(const UnicodeString & Section, const UnicodeString & Ident)
+{
+  UnicodeString Result = Section;
+  if (!Result.IsEmpty())
+  {
+    Result += PathDelim;
+  }
+  Result += Ident; // Can be empty, when called from a contructor, AllowSection or ReadSection
+  if (DebugAlwaysTrue(AllowSection(Section)))
+  {
+    Result.Delete(1, FRootKey.Length());
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+UnicodeString __fastcall TOptionsIniFile::ReadString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Default)
+{
   UnicodeString Value;
-  if (!SameText(Name.SubString(1, FRootKey.Length()), FRootKey))
+  if (!AllowSection(Section))
   {
     Value = Default;
   }
   else
   {
-    Name.Delete(1, FRootKey.Length());
-    Name += Ident;
+    UnicodeString Name = FormatKey(Section, Ident);
 
     int Index = FOptions->IndexOfName(Name);
     if (Index >= 0)
@@ -1406,25 +1428,19 @@ UnicodeString __fastcall TOptionsIniFile::ReadString(const UnicodeString Section
 void __fastcall TOptionsIniFile::WriteString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Value)
 {
   if (AllowWrite() &&
-      // Implemented for TSessionData.DoSave only
-      DebugAlwaysTrue(Section.IsEmpty() && FRootKey.IsEmpty()))
+      DebugAlwaysTrue(AllowSection(Section)))
   {
-    FOptions->Values[Ident] = Value;
+    UnicodeString Name = FormatKey(Section, Ident);
+    FOptions->Values[Name] = Value;
   }
 }
 //---------------------------------------------------------------------------
 void __fastcall TOptionsIniFile::ReadSection(const UnicodeString Section, TStrings * Strings)
 {
 
-  UnicodeString SectionPrefix = Section;
-  if (!SectionPrefix.IsEmpty())
+  if (AllowSection(Section))
   {
-    SectionPrefix += PathDelim;
-  }
-
-  if (SameText(SectionPrefix.SubString(1, FRootKey.Length()), FRootKey))
-  {
-    SectionPrefix.Delete(1, FRootKey.Length());
+    UnicodeString SectionPrefix = FormatKey(Section, UnicodeString());
 
     Strings->BeginUpdate();
     try
@@ -1486,10 +1502,11 @@ void __fastcall TOptionsIniFile::EraseSection(const UnicodeString Section)
 void __fastcall TOptionsIniFile::DeleteKey(const UnicodeString Section, const UnicodeString Ident)
 {
   if (AllowWrite() &&
-      // Implemented for TSessionData.DoSave only
-      DebugAlwaysTrue(Section.IsEmpty() && FRootKey.IsEmpty()))
+      DebugAlwaysTrue(AllowSection(Section)))
   {
-    int Index = FOptions->IndexOfName(Ident);
+    UnicodeString Name = FormatKey(Section, Ident);
+
+    int Index = FOptions->IndexOfName(Name);
     if (Index >= 0)
     {
       FOptions->Delete(Index);

+ 2 - 11
source/core/SessionData.cpp

@@ -881,6 +881,7 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage, bool PuttyImp
 void __fastcall TSessionData::DoSave(THierarchicalStorage * Storage,
   bool PuttyExport, const TSessionData * Default, bool DoNotEncryptPasswords)
 {
+  // Same as in TCopyParamType::Save
   #define WRITE_DATA_EX(TYPE, NAME, PROPERTY, CONV) \
     if ((Default != NULL) && (CONV(Default->PROPERTY) == CONV(PROPERTY))) \
     { \
@@ -3042,17 +3043,7 @@ UnicodeString __fastcall TSessionData::GenerateOpenCommandArgs(bool Rtf)
   {
     AddSwitch(Result, RawSettingsOption, Rtf);
 
-    for (int Index = 0; Index < RawSettings->Count; Index++)
-    {
-      UnicodeString Name = RawSettings->Names[Index];
-      UnicodeString Value = RawSettings->ValueFromIndex[Index];
-      // Do not quote if it is all-numeric
-      if (IntToStr(StrToIntDef(Value, -1)) != Value)
-      {
-        Value = FORMAT(L"\"%s\"", (EscapeParam(Value)));
-      }
-      Result += FORMAT(L" %s=%s", (Name, Value));
-    }
+    Result += StringsToParams(RawSettings.get());
   }
 
   return Result;

+ 57 - 21
source/forms/CustomScpExplorer.cpp

@@ -4582,31 +4582,34 @@ void __fastcall TCustomScpExplorerForm::NewSession(bool FromSite, const UnicodeS
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TCustomScpExplorerForm::DuplicateSession()
+UnicodeString __fastcall TCustomScpExplorerForm::CreateHiddenDuplicateSession()
 {
+  UnicodeString SessionName = StoredSessions->HiddenPrefix + Terminal->SessionData->SessionName;
+
   // current working directories become defaults here, what is not right
-  TSessionData * SessionData = CloneCurrentSessionData();
-  try
+  std::unique_ptr<TSessionData> SessionData(CloneCurrentSessionData());
+  StoredSessions->NewSession(SessionName, SessionData.get());
+  // modified only, explicit
+  StoredSessions->Save(false, true);
+
+  // encode session name because of slashes in hierarchical sessions
+  return EncodeUrlString(SessionName);
+}
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::DuplicateSession()
+{
+  if (OpenInNewWindow())
   {
-    if (OpenInNewWindow())
-    {
-      UnicodeString SessionName = StoredSessions->HiddenPrefix + Terminal->SessionData->SessionName;
-      StoredSessions->NewSession(SessionName, SessionData);
-      // modified only, explicit
-      StoredSessions->Save(false, true);
-      // encode session name because of slashes in hierarchical sessions
-      ExecuteNewInstance(EncodeUrlString(SessionName));
-    }
-    else
-    {
-      TTerminalManager * Manager = TTerminalManager::Instance();
-      TTerminal * Terminal = Manager->NewTerminal(SessionData);
-      Manager->ActiveTerminal = Terminal;
-    }
+    ExecuteNewInstance(CreateHiddenDuplicateSession());
   }
-  __finally
+  else
   {
-    delete SessionData;
+    // current working directories become defaults here, what is not right
+    std::unique_ptr<TSessionData> SessionData(CloneCurrentSessionData());
+
+    TTerminalManager * Manager = TTerminalManager::Instance();
+    TTerminal * Terminal = Manager->NewTerminal(SessionData.get());
+    Manager->ActiveTerminal = Terminal;
   }
 }
 //---------------------------------------------------------------------------
@@ -5034,7 +5037,7 @@ bool __fastcall TCustomScpExplorerForm::DoSynchronizeDirectories(
     DebugAssert(FOnFeedSynchronizeError == NULL);
     Result = DoSynchronizeDialog(Params, &CopyParam, Controller.StartStop,
       SaveSettings, Options, CopyParamAttrs, GetSynchronizeOptions, SynchronizeSessionLog,
-      FOnFeedSynchronizeError, UseDefaults);
+      FOnFeedSynchronizeError, SynchronizeInNewWindow, UseDefaults);
     if (Result)
     {
       if (SaveSettings)
@@ -5255,6 +5258,39 @@ void __fastcall TCustomScpExplorerForm::GetSynchronizeOptions(
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::SynchronizeInNewWindow(
+  const TSynchronizeParamType & Params, const TCopyParamType * CopyParams)
+{
+  UnicodeString SessionName = CreateHiddenDuplicateSession();
+
+  UnicodeString AdditionalParams =
+    FORMAT(L"%s \"%s\" \"%s\" %d %d %s", (
+      TProgramParams::FormatSwitch(KEEP_UP_TO_DATE_SWITCH),
+      Params.LocalDirectory, Params.RemoteDirectory, Params.Params, Params.Options,
+      TProgramParams::FormatSwitch(DEFAULTS_SWITCH)));
+
+  TCopyParamType Defaults;
+  std::unique_ptr<THierarchicalStorage> ConfigStorage(Configuration->CreateConfigStorage());
+  ConfigStorage->AccessMode = smRead;
+  if (ConfigStorage->OpenSubKey(Configuration->ConfigurationSubKey, false, false))
+  {
+    GUIConfiguration->LoadCopyParam(ConfigStorage.get(), &Defaults);
+  }
+  ConfigStorage.reset(NULL);
+
+  std::unique_ptr<TStringList> Options(new TStringList());
+  std::unique_ptr<TOptionsStorage> OptionsStorage(new TOptionsStorage(Options.get(), true));
+  GUIConfiguration->SaveCopyParam(OptionsStorage.get(), CopyParams, &Defaults);
+
+  if (Options->Count > 0)
+  {
+    AdditionalParams +=
+      FORMAT(L" %s%s", (TProgramParams::FormatSwitch(RAW_CONFIG_SWITCH), StringsToParams(Options.get())));
+  }
+
+  ExecuteNewInstance(SessionName, AdditionalParams);
+}
+//---------------------------------------------------------------------------
 bool __fastcall TCustomScpExplorerForm::DoFullSynchronizeDirectories(
   UnicodeString & LocalDirectory, UnicodeString & RemoteDirectory,
   TSynchronizeMode & Mode, bool & SaveMode, bool UseDefaults)

+ 2 - 0
source/forms/CustomScpExplorer.h

@@ -414,6 +414,7 @@ protected:
     TSynchronizeOptions * Options);
   void __fastcall SynchronizeSessionLog(const UnicodeString & Message);
   void __fastcall GetSynchronizeOptions(int Params, TSynchronizeOptions & Options);
+  void __fastcall SynchronizeInNewWindow(const TSynchronizeParamType & Params, const TCopyParamType * CopyParams);
   bool __fastcall SynchronizeAllowSelectedOnly();
   virtual void __fastcall BatchStart(void *& Storage);
   virtual void __fastcall BatchEnd(void * Storage);
@@ -633,6 +634,7 @@ public:
   void __fastcall Idle();
   __fastcall TCustomScpExplorerForm(TComponent* Owner);
   void __fastcall SaveCurrentSession();
+  UnicodeString __fastcall CreateHiddenDuplicateSession();
   TSessionData * __fastcall CloneCurrentSessionData();
   bool __fastcall SaveWorkspace(bool EnableAutoSave);
   virtual void __fastcall CompareDirectories();

+ 53 - 5
source/forms/Synchronize.cpp

@@ -17,6 +17,7 @@
 #include <HelpWin.h>
 #include <WinConfiguration.h>
 #include <StrUtils.hpp>
+#include <Tools.h>
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 #pragma link "HistoryComboBox"
@@ -33,12 +34,13 @@ bool __fastcall DoSynchronizeDialog(TSynchronizeParamType & Params,
   TGetSynchronizeOptionsEvent OnGetOptions,
   TSynchronizeSessionLog OnSynchronizeSessionLog,
   TFeedSynchronizeError & OnFeedSynchronizeError,
+  TSynchronizeInNewWindow OnSynchronizeInNewWindow,
   bool Start)
 {
   bool Result;
   TSynchronizeDialog * Dialog = SafeFormCreate<TSynchronizeDialog>(Application);
 
-  Dialog->Init(OnStartStop, OnGetOptions, OnSynchronizeSessionLog, OnFeedSynchronizeError, Start);
+  Dialog->Init(OnStartStop, OnGetOptions, OnSynchronizeSessionLog, OnFeedSynchronizeError, OnSynchronizeInNewWindow, Start);
 
   try
   {
@@ -94,12 +96,15 @@ void __fastcall TSynchronizeDialog::Init(TSynchronizeStartStopEvent OnStartStop,
   TGetSynchronizeOptionsEvent OnGetOptions,
   TSynchronizeSessionLog OnSynchronizeSessionLog,
   TFeedSynchronizeError & OnFeedSynchronizeError,
+  TSynchronizeInNewWindow OnSynchronizeInNewWindow,
   bool StartImmediately)
 {
   FOnStartStop = OnStartStop;
   FOnGetOptions = OnGetOptions;
   FOnSynchronizeSessionLog = OnSynchronizeSessionLog;
   FOnFeedSynchronizeError = &OnFeedSynchronizeError;
+  DebugAssert(OnSynchronizeInNewWindow != NULL);
+  FOnSynchronizeInNewWindow = OnSynchronizeInNewWindow;
   FStartImmediately = StartImmediately;
 }
 //---------------------------------------------------------------------------
@@ -180,6 +185,13 @@ void __fastcall TSynchronizeDialog::UpdateControls()
   // When minimizing to tray globally, no point showing special "minimize to tray" command
   MinimizeButton->Style =
     !WinConfiguration->MinimizeToTray ? TCustomButton::bsSplitButton : TCustomButton::bsPushButton;
+
+  StartButton->Style = AllowStartInNewWindow() ? TCustomButton::bsSplitButton : TCustomButton::bsPushButton;
+}
+//---------------------------------------------------------------------------
+bool __fastcall TSynchronizeDialog::AllowStartInNewWindow()
+{
+  return !IsMainFormLike(this);
 }
 //---------------------------------------------------------------------------
 void __fastcall TSynchronizeDialog::ControlChange(TObject * /*Sender*/)
@@ -391,6 +403,18 @@ void __fastcall TSynchronizeDialog::DoLog(TSynchronizeController * /*Controller*
 }
 //---------------------------------------------------------------------------
 void __fastcall TSynchronizeDialog::StartButtonClick(TObject * /*Sender*/)
+{
+  if (AllowStartInNewWindow() && OpenInNewWindow())
+  {
+    StartInNewWindow();
+  }
+  else
+  {
+    Start();
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TSynchronizeDialog::Start()
 {
   bool Synchronize;
   bool Continue = true;
@@ -428,10 +452,7 @@ void __fastcall TSynchronizeDialog::StartButtonClick(TObject * /*Sender*/)
   {
     DebugAssert(!FSynchronizing);
 
-    LocalDirectoryEdit->SaveToHistory();
-    CustomWinConfiguration->History[L"LocalDirectory"] = LocalDirectoryEdit->Items;
-    RemoteDirectoryEdit->SaveToHistory();
-    CustomWinConfiguration->History[L"RemoteDirectory"] = RemoteDirectoryEdit->Items;
+    SaveHistory();
 
     FSynchronizing = true;
     try
@@ -451,6 +472,14 @@ void __fastcall TSynchronizeDialog::StartButtonClick(TObject * /*Sender*/)
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TSynchronizeDialog::SaveHistory()
+{
+  LocalDirectoryEdit->SaveToHistory();
+  CustomWinConfiguration->History[L"LocalDirectory"] = LocalDirectoryEdit->Items;
+  RemoteDirectoryEdit->SaveToHistory();
+  CustomWinConfiguration->History[L"RemoteDirectory"] = RemoteDirectoryEdit->Items;
+}
+//---------------------------------------------------------------------------
 void __fastcall TSynchronizeDialog::StopButtonClick(TObject * /*Sender*/)
 {
   Stop();
@@ -692,3 +721,22 @@ void __fastcall TSynchronizeDialog::MinimizeButtonDropDownClick(TObject * /*Send
   MenuPopup(MinimizeMenu, MinimizeButton);
 }
 //---------------------------------------------------------------------------
+void __fastcall TSynchronizeDialog::StartInNewWindow1Click(TObject * /*Sender*/)
+{
+  StartInNewWindow();
+}
+//---------------------------------------------------------------------------
+void __fastcall TSynchronizeDialog::StartInNewWindow()
+{
+  SaveHistory();
+  TSynchronizeParamType AParams = Params;
+  TCopyParamType ACopyParams = CopyParams;
+  FOnSynchronizeInNewWindow(AParams, &ACopyParams);
+  Close();
+}
+//---------------------------------------------------------------------------
+void __fastcall TSynchronizeDialog::StartButtonDropDownClick(TObject * /*Sender*/)
+{
+  MenuPopup(StartMenu, StartButton);
+}
+//---------------------------------------------------------------------------

+ 14 - 0
source/forms/Synchronize.dfm

@@ -201,6 +201,7 @@ object SynchronizeDialog: TSynchronizeDialog
     Default = True
     TabOrder = 3
     OnClick = StartButtonClick
+    OnDropDownClick = StartButtonDropDownClick
   end
   object MinimizeButton: TButton
     Left = 277
@@ -312,4 +313,17 @@ object SynchronizeDialog: TSynchronizeDialog
       OnClick = MinimizetoTray1Click
     end
   end
+  object StartMenu: TPopupMenu
+    Left = 288
+    Top = 376
+    object Start1: TMenuItem
+      Caption = '&Start'
+      Default = True
+      OnClick = StartButtonClick
+    end
+    object StartInNewWindow1: TMenuItem
+      Caption = 'Start in &New Window'
+      OnClick = StartInNewWindow1Click
+    end
+  end
 end

+ 13 - 4
source/forms/Synchronize.h

@@ -48,6 +48,9 @@ __published:
   TPopupMenu *MinimizeMenu;
   TMenuItem *Minimize1;
   TMenuItem *MinimizetoTray1;
+  TPopupMenu *StartMenu;
+  TMenuItem *Start1;
+  TMenuItem *StartInNewWindow1;
   void __fastcall ControlChange(TObject *Sender);
   void __fastcall LocalDirectoryBrowseButtonClick(TObject *Sender);
   void __fastcall TransferSettingsButtonClick(TObject *Sender);
@@ -72,6 +75,8 @@ __published:
   void __fastcall Minimize1Click(TObject *Sender);
   void __fastcall MinimizetoTray1Click(TObject *Sender);
   void __fastcall MinimizeButtonDropDownClick(TObject *Sender);
+  void __fastcall StartInNewWindow1Click(TObject *Sender);
+  void __fastcall StartButtonDropDownClick(TObject *Sender);
 
 private:
   TSynchronizeParamType FParams;
@@ -90,6 +95,7 @@ private:
   UnicodeString FPreset;
   TSynchronizeOptions * FSynchronizeOptions;
   TFeedSynchronizeError * FOnFeedSynchronizeError;
+  TSynchronizeInNewWindow FOnSynchronizeInNewWindow;
   static const MaxLogItems;
 
   void __fastcall SetParams(const TSynchronizeParamType& value);
@@ -121,13 +127,19 @@ protected:
     const UnicodeString & HelpKeyword);
   TLogItemData * __fastcall GetLogItemData(TListItem * Item);
   void __fastcall Minimize(TObject * Sender);
+  void __fastcall Start();
+  void __fastcall StartInNewWindow();
+  void __fastcall SaveHistory();
+  void __fastcall UpdateControls();
+  bool __fastcall AllowStartInNewWindow();
 
 public:
   __fastcall TSynchronizeDialog(TComponent * Owner);
   void __fastcall Init(TSynchronizeStartStopEvent OnStartStop,
     TGetSynchronizeOptionsEvent OnGetOptions,
     TSynchronizeSessionLog OnSynchronizeSessionLog,
-    TFeedSynchronizeError & OnFeedSynchronizeError, bool StartImmediately);
+    TFeedSynchronizeError & OnFeedSynchronizeError, TSynchronizeInNewWindow OnSynchronizeInNewWindow,
+    bool StartImmediately);
   virtual __fastcall ~TSynchronizeDialog();
 
   bool __fastcall Execute();
@@ -137,9 +149,6 @@ public:
   __property int Options = { read = FOptions, write = SetOptions };
   __property int CopyParamAttrs = { read = FCopyParamAttrs, write = FCopyParamAttrs };
   __property TCopyParamType CopyParams = { read = GetCopyParams, write = SetCopyParams };
-
-protected:
-  void __fastcall UpdateControls();
 };
 //---------------------------------------------------------------------------
 #endif

+ 6 - 6
source/windows/ConsoleRunner.cpp

@@ -2187,8 +2187,8 @@ void __fastcall Usage(TConsole * Console)
     PrintUsageSyntax(Console, FORMAT(L"[mysession] /%s=<name>", (LowerCase(SESSIONNAME_SWICH))));
     PrintUsageSyntax(Console, L"[mysession] /newinstance");
     PrintUsageSyntax(Console, L"[mysession] /edit <path>");
-    PrintUsageSyntax(Console, L"[mysession] /synchronize [local_dir] [remote_dir] [/defaults]");
-    PrintUsageSyntax(Console, L"[mysession] /keepuptodate [local_dir] [remote_dir] [/defaults]");
+    PrintUsageSyntax(Console, FORMAT(L"[mysession] /synchronize [local_dir] [remote_dir] [/%s]", (LowerCase(DEFAULTS_SWITCH))));
+    PrintUsageSyntax(Console, FORMAT(L"[mysession] /%s [local_dir] [remote_dir] [/%s]", (LowerCase(KEEP_UP_TO_DATE_SWITCH), LowerCase(DEFAULTS_SWITCH))));
     PrintUsageSyntax(Console, FORMAT(L"[mysession] /%s [path]", (LowerCase(REFRESH_SWITCH))));
     PrintUsageSyntax(Console, L"[mysession] [/privatekey=<file>] [/hostkey=<fingerprint>]");
     PrintUsageSyntax(Console, L"[mysession] [/clientcert=<file>] [/certificate=<fingerprint>]");
@@ -2204,7 +2204,7 @@ void __fastcall Usage(TConsole * Console)
   PrintUsageSyntax(Console, L"[/xmllog=<logfile> [/xmlgroups]]");
   PrintUsageSyntax(Console,
     FORMAT(L"[/%s=<inifile>]", (LowerCase(INI_SWITCH))));
-  PrintUsageSyntax(Console, L"[/rawconfig config1=value1 config2=value2 ...]");
+  PrintUsageSyntax(Console, FORMAT(L"[/%s config1=value1 config2=value2 ...]", (LowerCase(RAW_CONFIG_SWITCH))));
   PrintUsageSyntax(Console, L"/batchsettings <site_mask> setting1=value1 setting2=value2 ...");
   PrintUsageSyntax(Console, FORMAT(L"/%s keyfile [/%s=output] [/%s] [/%s=comment]",
     (LowerCase(KEYGEN_SWITCH), LowerCase(KEYGEN_OUTPUT_SWITCH), LowerCase(KEYGEN_CHANGE_PASSPHRASE_SWITCH), LowerCase(KEYGEN_COMMENT_SWITCH))));
@@ -2224,9 +2224,9 @@ void __fastcall Usage(TConsole * Console)
     RegisterSwitch(SwitchesUsage, L"/newinstance", USAGE_NEWINSTANCE);
     RegisterSwitch(SwitchesUsage, L"/edit", USAGE_EDIT);
     RegisterSwitch(SwitchesUsage, L"/synchronize", USAGE_SYNCHRONIZE);
-    RegisterSwitch(SwitchesUsage, L"/keepuptodate", USAGE_KEEPUPTODATE);
+    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(KEEP_UP_TO_DATE_SWITCH), USAGE_KEEPUPTODATE);
     RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(REFRESH_SWITCH), USAGE_REFRESH);
-    RegisterSwitch(SwitchesUsage, L"/defaults", USAGE_DEFAULTS);
+    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(DEFAULTS_SWITCH), USAGE_DEFAULTS);
     RegisterSwitch(SwitchesUsage, L"/privatekey=", USAGE_PRIVATEKEY);
     RegisterSwitch(SwitchesUsage, L"/hostkey=", USAGE_HOSTKEY);
     RegisterSwitch(SwitchesUsage, L"/clientcert=", USAGE_CLIENTCERT);
@@ -2247,7 +2247,7 @@ void __fastcall Usage(TConsole * Console)
   RegisterSwitch(SwitchesUsage, L"/xmllog=", USAGE_XMLLOG);
   RegisterSwitch(SwitchesUsage, L"/xmlgroups", USAGE_XMLGROUPS);
   RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(INI_SWITCH) + L"=", USAGE_INI);
-  RegisterSwitch(SwitchesUsage, L"/rawconfig", USAGE_RAWCONFIG);
+  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(RAW_CONFIG_SWITCH), USAGE_RAWCONFIG);
   RegisterSwitch(SwitchesUsage, L"/batchsettings", USAGE_BATCHSETTINGS);
   UnicodeString KeyGenDesc =
     FMTLOAD(USAGE_KEYGEN, (

+ 42 - 5
source/windows/GUIConfiguration.cpp

@@ -652,6 +652,26 @@ void __fastcall TGUIConfiguration::UpdateStaticUsage()
     KEY(Integer,  SessionReopenAutoIdle); \
   ); \
 //---------------------------------------------------------------------------
+bool __fastcall TGUIConfiguration::DoSaveCopyParam(THierarchicalStorage * Storage, const TCopyParamType * CopyParam, const TCopyParamType * Defaults)
+{
+  bool Result = Storage->OpenSubKey(L"Interface\\CopyParam", true, true);
+  if (Result)
+  {
+    CopyParam->Save(Storage, Defaults);
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+bool __fastcall TGUIConfiguration::SaveCopyParam(THierarchicalStorage * Storage, const TCopyParamType * CopyParam, const TCopyParamType * Defaults)
+{
+  bool Result = DoSaveCopyParam(Storage, CopyParam, Defaults);
+  if (Result)
+  {
+    Storage->CloseSubKey();
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 void __fastcall TGUIConfiguration::SaveData(THierarchicalStorage * Storage, bool All)
 {
   TConfiguration::SaveData(Storage, All);
@@ -661,7 +681,7 @@ void __fastcall TGUIConfiguration::SaveData(THierarchicalStorage * Storage, bool
   REGCONFIG(true);
   #undef KEYEX
 
-  if (Storage->OpenSubKey(L"Interface\\CopyParam", true, true))
+  if (DoSaveCopyParam(Storage, &FDefaultCopyParam, NULL))
   try
   {
     FDefaultCopyParam.Save(Storage);
@@ -693,6 +713,25 @@ void __fastcall TGUIConfiguration::SaveData(THierarchicalStorage * Storage, bool
   }
 }
 //---------------------------------------------------------------------------
+bool __fastcall TGUIConfiguration::LoadCopyParam(THierarchicalStorage * Storage, TCopyParamType * CopyParam)
+{
+  bool Result =
+    Storage->OpenSubKey(L"Interface\\CopyParam", false, true);
+  if (Result)
+  {
+    try
+    {
+      CopyParam->Load(Storage);
+    }
+    catch (...)
+    {
+      Storage->CloseSubKey();
+      throw;
+    }
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 void __fastcall TGUIConfiguration::LoadData(THierarchicalStorage * Storage)
 {
   TConfiguration::LoadData(Storage);
@@ -704,12 +743,10 @@ void __fastcall TGUIConfiguration::LoadData(THierarchicalStorage * Storage)
   #pragma warn +eas
   #undef KEYEX
 
-  if (Storage->OpenSubKey(L"Interface\\CopyParam", false, true))
+  // FDefaultCopyParam must be loaded before eventual setting defaults for CopyParamList
+  if (LoadCopyParam(Storage, &FDefaultCopyParam))
   try
   {
-    // must be loaded before eventual setting defaults for CopyParamList
-    FDefaultCopyParam.Load(Storage);
-
     int CopyParamListCount = Storage->ReadInteger(L"CopyParamList", -1);
     FCopyParamListDefaults = (CopyParamListCount < 0);
     if (!FCopyParamListDefaults)

+ 3 - 0
source/windows/GUIConfiguration.h

@@ -231,12 +231,15 @@ protected:
   virtual int __fastcall GetResourceModuleCompleteness(HINSTANCE Module);
   virtual bool __fastcall IsTranslationComplete(HINSTANCE Module);
   static int __fastcall LocalesCompare(void * Item1, void * Item2);
+  bool __fastcall DoSaveCopyParam(THierarchicalStorage * Storage, const TCopyParamType * CopyParam, const TCopyParamType * Defaults);
 
 public:
   __fastcall TGUIConfiguration();
   virtual __fastcall ~TGUIConfiguration();
   virtual void __fastcall Default();
   virtual void __fastcall UpdateStaticUsage();
+  bool __fastcall SaveCopyParam(THierarchicalStorage * Storage, const TCopyParamType * CopyParam, const TCopyParamType * Defaults);
+  bool __fastcall LoadCopyParam(THierarchicalStorage * Storage, TCopyParamType * CopyParam);
 
   HANDLE __fastcall ChangeToDefaultResourceModule();
   HANDLE __fastcall ChangeResourceModule(HANDLE Instance);

+ 5 - 1
source/windows/Tools.cpp

@@ -441,12 +441,16 @@ bool __fastcall OpenInNewWindow()
   return UseAlternativeFunction();
 }
 //---------------------------------------------------------------------------
-void __fastcall ExecuteNewInstance(const UnicodeString & Param)
+void __fastcall ExecuteNewInstance(const UnicodeString & Param, const UnicodeString & AdditionalParams)
 {
   UnicodeString Arg = Param;
   if (!Arg.IsEmpty())
   {
     Arg = FORMAT(L"\"%s\" %s", (Arg, TProgramParams::FormatSwitch(NEWINSTANCE_SWICH)));
+    if (!AdditionalParams.IsEmpty())
+    {
+      Arg += L" " + AdditionalParams;
+    }
   }
 
   ExecuteShellChecked(Application->ExeName, Arg);

+ 1 - 1
source/windows/Tools.h

@@ -17,7 +17,7 @@ void __fastcall ExecuteProcessCheckedAndWait(
 bool __fastcall IsKeyPressed(int VirtualKey);
 bool __fastcall UseAlternativeFunction();
 bool __fastcall OpenInNewWindow();
-void __fastcall ExecuteNewInstance(const UnicodeString & Param);
+void __fastcall ExecuteNewInstance(const UnicodeString & Param, const UnicodeString & AdditionalParams = UnicodeString());
 IShellLink * __fastcall CreateDesktopShortCut(const UnicodeString &Name,
   const UnicodeString &File, const UnicodeString & Params, const UnicodeString & Description,
   int SpecialFolder = -1, int IconIndex = 0, bool Return = false);

+ 1 - 1
source/windows/UserInterface.cpp

@@ -52,7 +52,7 @@ TConfiguration * __fastcall CreateConfiguration()
   if (CheckSafe(Params))
   {
     std::unique_ptr<TStrings> RawConfig(new TStringList());
-    if (Params->FindSwitch(L"rawconfig", RawConfig.get()))
+    if (Params->FindSwitch(RAW_CONFIG_SWITCH, RawConfig.get()))
     {
       WinConfiguration->OptionsStorage = RawConfig.get();
     }

+ 1 - 0
source/windows/VCLCommon.h

@@ -33,6 +33,7 @@ void __fastcall FixComboBoxResizeBug(TCustomComboBox * ComboBox);
 void __fastcall ShowAsModal(TForm * Form, void *& Storage, bool BringToFront = true);
 void __fastcall HideAsModal(TForm * Form, void *& Storage);
 bool __fastcall ReleaseAsModal(TForm * Form, void *& Storage);
+bool __fastcall IsMainFormLike(TCustomForm * Form);
 bool __fastcall SelectDirectory(UnicodeString & Path, const UnicodeString Prompt,
   bool PreserveFileName);
 enum TListViewCheckAll { caCheck, caUncheck, caToggle };

+ 6 - 0
source/windows/WinInterface.h

@@ -25,10 +25,12 @@ const int mpAllowContinueOnError = 0x02;
 
 #define UPLOAD_IF_ANY_SWITCH L"UploadIfAny"
 #define UPLOAD_SWITCH L"Upload"
+#define KEEP_UP_TO_DATE_SWITCH L"KeepUpToDate"
 #define JUMPLIST_SWITCH L"JumpList"
 #define DESKTOP_SWITCH L"Desktop"
 #define SEND_TO_HOOK_SWITCH L"SendToHook"
 #define UNSAFE_SWITCH L"Unsafe"
+#define DEFAULTS_SWITCH L"Defaults"
 #define NEWINSTANCE_SWICH L"NewInstance"
 #define KEYGEN_SWITCH L"KeyGen"
 #define KEYGEN_OUTPUT_SWITCH L"Output"
@@ -38,6 +40,7 @@ const int mpAllowContinueOnError = 0x02;
 #define LOGSIZE_SWITCH L"LogSize"
 #define LOGSIZE_SEPARATOR L"*"
 #define INI_SWITCH L"Ini"
+#define RAW_CONFIG_SWITCH L"RawConfig"
 #define FINGERPRINTSCAN_SWITCH L"FingerprintScan"
 
 struct TMessageParams
@@ -318,12 +321,15 @@ typedef void __fastcall (__closure *TSynchronizeSessionLog)
 typedef void __fastcall (__closure *TFeedSynchronizeError)
   (const UnicodeString & Message, TStrings * MoreMessages, TQueryType Type,
    const UnicodeString & HelpKeyword);
+typedef void __fastcall (__closure *TSynchronizeInNewWindow)
+  (const TSynchronizeParamType & Params, const TCopyParamType * CopyParams);
 bool __fastcall DoSynchronizeDialog(TSynchronizeParamType & Params,
   const TCopyParamType * CopyParams, TSynchronizeStartStopEvent OnStartStop,
   bool & SaveSettings, int Options, int CopyParamAttrs,
   TGetSynchronizeOptionsEvent OnGetOptions,
   TSynchronizeSessionLog OnSynchronizeSessionLog,
   TFeedSynchronizeError & OnFeedSynchronizeError,
+  TSynchronizeInNewWindow OnSynchronizeInNewWindow,
   bool Start);
 
 // forms\FullSynchronize.cpp

+ 11 - 2
source/windows/WinMain.cpp

@@ -247,6 +247,15 @@ void __fastcall Synchronize(TTerminal * Terminal, TCustomScpExplorerForm * ScpEx
 
   SynchronizeDirectories(Terminal, CommandParams, LocalDirectory, RemoteDirectory);
 
+  // Undocumented syntax for "Start in New Window"
+  if (CommandParams->Count >= 4)
+  {
+    GUIConfiguration->SynchronizeParams = StrToIntDef(CommandParams->Strings[2], -1);
+    GUIConfiguration->SynchronizeOptions = StrToIntDef(CommandParams->Strings[3], -1);
+
+    Configuration->DontSave();
+  }
+
   ScpExplorer->DoSynchronizeDirectories(LocalDirectory, RemoteDirectory, UseDefaults);
   Abort();
 }
@@ -934,7 +943,7 @@ int __fastcall Execute()
 
       if (!Params->Empty)
       {
-        if (Params->FindSwitch(L"Defaults") && CheckSafe(Params))
+        if (Params->FindSwitch(DEFAULTS_SWITCH) && CheckSafe(Params))
         {
           UseDefaults = true;
         }
@@ -958,7 +967,7 @@ int __fastcall Execute()
         {
           ParamCommand = pcFullSynchronize;
         }
-        else if (Params->FindSwitch(L"KeepUpToDate", CommandParams, 2))
+        else if (Params->FindSwitch(KEEP_UP_TO_DATE_SWITCH, CommandParams, 4))
         {
           ParamCommand = pcSynchronize;
         }