Browse Source

Bug 1701: Allow dropping remote files to network drives (and floppy drives) + Allow excluding certain drive letters from monitoring for dropped files + Better error message when drop target cannot be detected and drag&drop shell extension is not available

Source commit: 57d195f901e30a72e4e8dfaa45be586c5118334e
Martin Prikryl 7 years ago
parent
commit
55273790b0

+ 8 - 1
source/forms/CustomScpExplorer.cpp

@@ -7189,7 +7189,14 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDEnd(TObject * Sender)
             // as it is checked as soon as drag&drop starts from
             // RemoteFileControlDDCreateDragFileList
             Configuration->Usage->Inc(L"DownloadsDragDropExternalExtTargetUnknown");
-            throw ExtException(NULL, LoadStr(DRAGEXT_TARGET_UNKNOWN2), HELP_DRAGEXT_TARGET_UNKNOWN);
+            if (!WinConfiguration->DDExtInstalled || WinConfiguration->IsDDExtBroken())
+            {
+              throw ExtException(NULL, LoadStr(DD_TARGET_UNKNOWN), HELP_DD_TARGET_UNKNOWN);
+            }
+            else
+            {
+              throw ExtException(NULL, LoadStr(DRAGEXT_TARGET_UNKNOWN2), HELP_DRAGEXT_TARGET_UNKNOWN);
+            }
           }
         }
         else

+ 6 - 2
source/forms/Preferences.cpp

@@ -288,6 +288,7 @@ void __fastcall TPreferencesDialog::LoadConfiguration()
 
     DDFakeFileEnabledButton->Checked = WinConfiguration->DDFakeFile;
     DDFakeFileDisabledButton->Checked = !DDFakeFileEnabledButton->Checked;
+    DDDrivesMemo->Lines->CommaText = WinConfiguration->DDDrives;
 
     if (WinConfiguration->DDTemporaryDirectory.IsEmpty())
     {
@@ -663,6 +664,7 @@ void __fastcall TPreferencesDialog::SaveConfiguration()
     BOOLPROP(BalloonNotifications);
 
     WinConfiguration->DDFakeFile = DDFakeFileEnabledButton->Checked;
+    WinConfiguration->DDDrives = DDDrivesMemo->Lines->CommaText;
 
     if (DDSystemTemporaryDirectoryButton->Checked)
     {
@@ -1230,15 +1232,17 @@ void __fastcall TPreferencesDialog::UpdateControls()
     else if (!WinConfiguration->IsDDExtRunning())
     {
       DragExtStatusLabel->Caption = LoadStr(PREFERENCES_DRAGEXT_NOT_RUNNING);
-      DragExtStatusLabel->Enabled = true;
+      DragExtStatusLabel->Enabled = DDFakeFileEnabledButton->Checked;
       DragExtStatusLabel->Font->Color = clGrayText;
     }
     else
     {
       DragExtStatusLabel->Caption = LoadStr(PREFERENCES_DRAGEXT_RUNNING);
-      DragExtStatusLabel->Enabled = true;
+      DragExtStatusLabel->Enabled = DDFakeFileEnabledButton->Checked;
       DragExtStatusLabel->Font->Color = clWindowText;
     }
+    EnableControl(DDDrivesMemo, DDFakeFileEnabledButton->Checked);
+    EnableControl(DDDrivesLabel, DDDrivesMemo->Enabled);
     EnableControl(DDFakeFileDisabledPanel, DDFakeFileDisabledButton->Checked);
     EnableControl(DDTemporaryDirectoryEdit, DDCustomTemporaryDirectoryButton->Enabled &&
       DDCustomTemporaryDirectoryButton->Checked);

+ 26 - 9
source/forms/Preferences.dfm

@@ -1313,13 +1313,13 @@ object PreferencesDialog: TPreferencesDialog
           Left = 8
           Top = 8
           Width = 389
-          Height = 230
+          Height = 310
           Anchors = [akLeft, akTop, akRight]
           Caption = 'Drag && Drop downloads'
           TabOrder = 0
           DesignSize = (
             389
-            230)
+            310)
           object DDFakeFileEnabledLabel: TLabel
             Left = 35
             Top = 44
@@ -1337,7 +1337,7 @@ object PreferencesDialog: TPreferencesDialog
           end
           object DDFakeFileDisabledLabel: TLabel
             Left = 35
-            Top = 141
+            Top = 221
             Width = 346
             Height = 54
             Anchors = [akLeft, akTop, akRight]
@@ -1352,14 +1352,21 @@ object PreferencesDialog: TPreferencesDialog
           object DragExtStatusLabel: TLabel
             Left = 35
             Top = 96
-            Width = 345
-            Height = 26
+            Width = 95
+            Height = 13
             Anchors = [akLeft, akTop, akRight]
-            AutoSize = False
             Caption = 'DragExtStatusLabel'
-            WordWrap = True
             OnClick = DDLabelClick
           end
+          object DDDrivesLabel: TLabel
+            Left = 35
+            Top = 116
+            Width = 246
+            Height = 13
+            AutoSize = False
+            Caption = 'Allow dropping files to these &network drives:'
+            FocusControl = DDDrivesMemo
+          end
           object DDFakeFileEnabledButton: TRadioButton
             Left = 16
             Top = 24
@@ -1372,7 +1379,7 @@ object PreferencesDialog: TPreferencesDialog
           end
           object DDFakeFileDisabledButton: TRadioButton
             Left = 16
-            Top = 121
+            Top = 202
             Width = 356
             Height = 17
             Anchors = [akLeft, akTop, akRight]
@@ -1382,7 +1389,7 @@ object PreferencesDialog: TPreferencesDialog
           end
           object DDFakeFileDisabledPanel: TPanel
             Left = 34
-            Top = 192
+            Top = 272
             Width = 315
             Height = 28
             BevelOuter = bvNone
@@ -1401,6 +1408,16 @@ object PreferencesDialog: TPreferencesDialog
               OnClick = ControlChange
             end
           end
+          object DDDrivesMemo: TMemo
+            Left = 34
+            Top = 132
+            Width = 337
+            Height = 61
+            Lines.Strings = (
+              'DDDrivesMemo')
+            ScrollBars = ssVertical
+            TabOrder = 3
+          end
         end
       end
       object QueueSheet: TTabSheet

+ 2 - 0
source/forms/Preferences.h

@@ -320,6 +320,8 @@ __published:
   TCheckBox *NaturalOrderNumericalSortingCheck;
   TLabel *DragExtStatusLabel;
   TCheckBox *SynchronizeSummaryCheck;
+  TMemo *DDDrivesMemo;
+  TLabel *DDDrivesLabel;
   void __fastcall FormShow(TObject *Sender);
   void __fastcall ControlChange(TObject *Sender);
   void __fastcall EditorFontButtonClick(TObject *Sender);

+ 1 - 0
source/resource/HelpWin.h

@@ -62,5 +62,6 @@
 #define HELP_LOGIN_AUTHORIZED_KEYS   "guide_public_key"
 #define HELP_READONLY_INI_FILE       "config#ini_readonly"
 #define HELP_SESSION_RENAME          "task_connection"
+#define HELP_DD_TARGET_UNKNOWN       "dragdrop_download"
 
 #endif // TextsWin

+ 1 - 0
source/resource/TextsWin.h

@@ -89,6 +89,7 @@
 #define EXTENSION_INSTALLED_ALREADY 1206
 #define EXTENSION_LOAD_ERROR    1207
 #define NO_SITE_FOR_COMMAND     1208
+#define DD_TARGET_UNKNOWN       1209
 
 #define WIN_CONFIRMATION_STRINGS 1300
 #define CONFIRM_OVERWRITE_SESSION 1301

+ 1 - 0
source/resource/TextsWin1.rc

@@ -97,6 +97,7 @@ BEGIN
         EXTENSION_INSTALLED_ALREADY, "The extension is installed already."
         EXTENSION_LOAD_ERROR, "Error loading an extension from \"%s\"."
         NO_SITE_FOR_COMMAND, "**No session is opened**\nThe selected command has site-specific options, but no session is opened."
+        DD_TARGET_UNKNOWN, "**WinSCP was not able to detect a folder, where the dragged file(s) was dropped.** In the default drag&drop mode, WinSCP allows dropping files only to local drives and mapped nework drives.\n\nYou can allow dropping files to other targets in preferences. Press Help button for details."
 
         WIN_CONFIRMATION_STRINGS, "WIN_CONFIRMATION"
         CONFIRM_OVERWRITE_SESSION, "Site with name '%s' already exists. Overwrite?"

+ 49 - 18
source/windows/GUITools.cpp

@@ -6,7 +6,7 @@
 #include <Common.h>
 
 #include "GUITools.h"
-#include "GUIConfiguration.h"
+#include "WinConfiguration.h"
 #include <TextsCore.h>
 #include <CoreMain.h>
 #include <SessionData.h>
@@ -284,31 +284,62 @@ void __fastcall ExecuteTool(const UnicodeString & Name)
 //---------------------------------------------------------------------------
 TObjectList * StartCreationDirectoryMonitorsOnEachDrive(unsigned int Filter, TFileChangedEvent OnChanged)
 {
-  std::unique_ptr<TObjectList> Result(new TObjectList());
-  for (char Drive = FirstDrive; Drive <= LastDrive; Drive++)
+  std::unique_ptr<TStrings> Drives(new TStringList());
+
+  std::unique_ptr<TStrings> DDDrives(new TStringList());
+  DDDrives->CommaText = WinConfiguration->DDDrives;
+  UnicodeString ExcludedDrives;
+  for (int Index = 0; Index < DDDrives->Count; Index++)
   {
-    std::unique_ptr<TDirectoryMonitor> Monitor(new TDirectoryMonitor(Application));
-    TDriveInfoRec * DriveInfoRec = DriveInfo->Get(Drive);
-    if (DriveInfoRec->Valid &&
-        (DriveInfoRec->DriveType != DRIVE_CDROM) &&
-        ((DriveInfoRec->DriveType != DRIVE_REMOVABLE) || (Drive >= FirstFixedDrive)))
+    UnicodeString S = Trim(DDDrives->Strings[Index]);
+    if (!S.IsEmpty() && (S[1] == L'-'))
     {
-      try
+      S = Trim(S.SubString(2, S.Length() - 1));
+      if (!S.IsEmpty())
       {
-        Monitor->Path = DriveInfo->GetDriveRoot(Drive);
-        Monitor->WatchSubtree = true;
-        Monitor->WatchFilters = Filter;
-        Monitor->OnCreated = OnChanged;
-        Monitor->OnModified = OnChanged;
-        Monitor->Active = true;
-        Result->Add(Monitor.release());
+        ExcludedDrives += S[1];
       }
-      catch (Exception & E)
+    }
+    else
+    {
+      Drives->Add(S);
+    }
+  }
+
+  for (char Drive = FirstDrive; Drive <= LastDrive; Drive++)
+  {
+    if (ExcludedDrives.Pos(Drive) == 0)
+    {
+      TDriveInfoRec * DriveInfoRec = DriveInfo->Get(Drive);
+      if (DriveInfoRec->Valid &&
+          (DriveInfoRec->DriveType != DRIVE_CDROM) &&
+          ((DriveInfoRec->DriveType != DRIVE_REMOVABLE) || (Drive >= FirstFixedDrive)))
       {
-        // Ignore errors watching not-ready drives
+        Drives->Add(Drive);
       }
     }
   }
+
+  std::unique_ptr<TObjectList> Result(new TObjectList());
+  for (int Index = 0; Index < Drives->Count; Index++)
+  {
+    UnicodeString Drive = Drives->Strings[Index];
+    std::unique_ptr<TDirectoryMonitor> Monitor(new TDirectoryMonitor(Application));
+    try
+    {
+      Monitor->Path = DriveInfo->GetDriveRoot(Drive);
+      Monitor->WatchSubtree = true;
+      Monitor->WatchFilters = Filter;
+      Monitor->OnCreated = OnChanged;
+      Monitor->OnModified = OnChanged;
+      Monitor->Active = true;
+      Result->Add(Monitor.release());
+    }
+    catch (Exception & E)
+    {
+      // Ignore errors watching not-ready drives
+    }
+  }
   return Result.release();
 }
 //---------------------------------------------------------------------------

+ 7 - 0
source/windows/WinConfiguration.cpp

@@ -491,6 +491,7 @@ void __fastcall TWinConfiguration::Default()
 
   FDDTransferConfirmation = asAuto;
   FDDTemporaryDirectory = L"";
+  FDDDrives = L"";
   FDDWarnLackOfTempSpace = true;
   FDDWarnLackOfTempSpaceRatio = 1.1;
   FDDFakeFile = true;
@@ -895,6 +896,7 @@ THierarchicalStorage * TWinConfiguration::CreateScpStorage(bool & SessionList)
     KEY(Bool,     CopyOnDoubleClickConfirmation); \
     KEYEX(Integer, DDTransferConfirmation, L"DDTransferConfirmation2"); \
     KEY(String,   DDTemporaryDirectory); \
+    KEY(String,   DDDrives); \
     KEY(Bool,     DDWarnLackOfTempSpace); \
     KEY(Float,    DDWarnLackOfTempSpaceRatio); \
     KEY(Bool,     DeleteToRecycleBin); \
@@ -1831,6 +1833,11 @@ void __fastcall TWinConfiguration::SetDDTemporaryDirectory(UnicodeString value)
   SET_CONFIG_PROPERTY(DDTemporaryDirectory);
 }
 //---------------------------------------------------------------------------
+void __fastcall TWinConfiguration::SetDDDrives(UnicodeString value)
+{
+  SET_CONFIG_PROPERTY(DDDrives);
+}
+//---------------------------------------------------------------------------
 void __fastcall TWinConfiguration::SetDDFakeFile(bool value)
 {
   SET_CONFIG_PROPERTY(DDFakeFile);

+ 3 - 0
source/windows/WinConfiguration.h

@@ -353,6 +353,7 @@ private:
   bool FUseLocationProfiles;
   bool FUseSharedBookmarks;
   UnicodeString FDDTemporaryDirectory;
+  UnicodeString FDDDrives;
   bool FDDWarnLackOfTempSpace;
   bool FDDFakeFile;
   int FDDExtInstalled;
@@ -461,6 +462,7 @@ private:
   void __fastcall SetUseLocationProfiles(bool value);
   void __fastcall SetUseSharedBookmarks(bool value);
   void __fastcall SetDDTemporaryDirectory(UnicodeString value);
+  void __fastcall SetDDDrives(UnicodeString value);
   void __fastcall SetDDWarnLackOfTempSpace(bool value);
   void __fastcall SetDDFakeFile(bool value);
   void __fastcall SetDDExtTimeout(int value);
@@ -646,6 +648,7 @@ public:
   __property bool UseLocationProfiles = { read = FUseLocationProfiles, write = SetUseLocationProfiles};
   __property bool UseSharedBookmarks = { read = FUseSharedBookmarks, write = SetUseSharedBookmarks};
   __property UnicodeString DDTemporaryDirectory  = { read=FDDTemporaryDirectory, write=SetDDTemporaryDirectory };
+  __property UnicodeString DDDrives  = { read=FDDDrives, write=SetDDDrives };
   __property bool DDWarnLackOfTempSpace  = { read=FDDWarnLackOfTempSpace, write=SetDDWarnLackOfTempSpace };
   __property bool DDFakeFile = { read=FDDFakeFile, write=SetDDFakeFile };
   __property bool DDExtInstalled = { read=GetDDExtInstalled };