1
0
mirror of https://github.com/winscp/winscp.git synced 2026-10-24 02:28:55 +03:00
Files
winscp/source/forms/Custom.cpp
Martin Prikryl 27a9163e0b TPasswordEdit is not needed as VCL supports ES_PASSWORD style with TEdit
... and did already in XE6.
Getting rid of TPasswordEdit will also make it easier to subclass edits by reducing number of classes in use.

Source commit: 0f32c7a6cdb1bab0c966215770ea923cfdae5c58
2025-05-23 01:18:15 +02:00

1897 lines
63 KiB
C++

//---------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include <Dialogs.hpp>
//---------------------------------------------------------------------
#include <Common.h>
#include <CustomWinConfiguration.h>
#include <WinInterface.h>
#include <VCLCommon.h>
#include <TextsWin.h>
#include <HelpWin.h>
#include <CoreMain.h>
#include <PasTools.hpp>
#include <ProgParams.h>
#include <Tools.h>
#include <GUITools.h>
#include <PuttyTools.h>
#include <HistoryComboBox.hpp>
#include <Math.hpp>
#include <System.Character.hpp>
#include "Custom.h"
//---------------------------------------------------------------------
#pragma resource "*.dfm"
//---------------------------------------------------------------------
const int GroupBoxBorderWidth = 1;
//---------------------------------------------------------------------
__fastcall TCustomDialog::TCustomDialog(UnicodeString AHelpKeyword)
: TForm(GetFormOwner())
{
UseSystemSettings(this);
FControlPadding = ScaleByTextHeight(this, 6);
FPos = ScaleByTextHeight(this, 8);
FPrePos = FPos;
FHorizontalMargin = ScaleByTextHeight(this, 8);
FIndent = FHorizontalMargin;
FGroupBox = NULL;
HelpKeyword = AHelpKeyword;
TBorderIcons BI = BorderIcons;
if (HelpKeyword.IsEmpty())
{
BI >> biHelp;
OKButton->Left = CancelButton->Left;
CancelButton->Left = HelpButton->Left;
HelpButton->Visible = false;
}
else
{
BI << biHelp;
}
BorderIcons = BI;
}
//---------------------------------------------------------------------
bool __fastcall TCustomDialog::Execute()
{
Changed();
return (ShowModal() == DefaultResult(this));
}
//---------------------------------------------------------------------
void __fastcall TCustomDialog::DoChange(bool & /*CanSubmit*/)
{
// noop
}
//---------------------------------------------------------------------
void __fastcall TCustomDialog::Changed()
{
bool CanSubmit = true;
DoChange(CanSubmit);
EnableControl(OKButton, CanSubmit);
}
//---------------------------------------------------------------------
void __fastcall TCustomDialog::Change(TObject * /*Sender*/)
{
Changed();
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::DoHelp()
{
FormHelp(this);
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::HelpButtonClick(TObject * /*Sender*/)
{
DoHelp();
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::DoShow()
{
OKButton->TabOrder = FCount;
CancelButton->TabOrder = static_cast<short>(FCount + 1);
HelpButton->TabOrder = static_cast<short>(FCount + 2);
Changed();
TForm::DoShow();
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::DoValidate()
{
// noop
}
//---------------------------------------------------------------------------
bool __fastcall TCustomDialog::CloseQuery()
{
if (ModalResult == DefaultResult(this))
{
DoValidate();
}
return TForm::CloseQuery();
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::RemoveCancelButton()
{
CancelButton->Visible = false;
OKButton->Left = CancelButton->Left;
OKButton->Cancel = true;
DebugAssert(OKButton->Width == CancelButton->Width);
DebugAssert(OKButton->Top == CancelButton->Top);
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::AddDialogButton(TButton * Button)
{
Button->Parent = this;
Button->Top = OKButton->Top;
Button->Left = FHorizontalMargin;
Button->Height = OKButton->Height;
AddWinControl(Button);
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::AddImage(const UnicodeString & ImageName)
{
TImage * Image = new TImage(this);
Image->Name = L"Image";
Image->Parent = GetDefaultParent();
LoadDialogImage(Image, ImageName);
Image->SetBounds(FIndent, FPos + ScaleByTextHeight(this, 3), Image->Picture->Width, Image->Picture->Height);
FIndent += Image->Width + ScaleByTextHeight(this, 12);
}
//---------------------------------------------------------------------------
int __fastcall TCustomDialog::GetMaxControlWidth(TControl * Control)
{
return GetDefaultParent()->ClientWidth - Control->Left - FHorizontalMargin - (FGroupBox != NULL ? GroupBoxBorderWidth : 0);
}
//---------------------------------------------------------------------------
TWinControl * __fastcall TCustomDialog::GetDefaultParent()
{
return (FGroupBox != NULL) ? FGroupBox : static_cast<TWinControl *>(this);
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::AdjustHeight(TControl * Control)
{
FPos = Control->Top + Control->Height + FControlPadding;
int Delta = (FPos - FPrePos);
ClientHeight = ClientHeight + Delta;
if (FGroupBox != NULL)
{
FGroupBox->Height = FGroupBox->Height + Delta;
}
FPrePos = FPos;
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::AddWinControl(TWinControl * Control)
{
Control->TabOrder = FCount;
FCount++;
}
//---------------------------------------------------------------------------
TCheckBox * __fastcall TCustomDialog::CreateAndAddCheckBox(const UnicodeString & Caption)
{
TCheckBox * CheckBox = new TCheckBox(this);
CheckBox->Caption = Caption;
AddButtonControl(CheckBox);
return CheckBox;
}
//---------------------------------------------------------------------------
TLabel * __fastcall TCustomDialog::CreateLabel(UnicodeString Label)
{
TLabel * Result = ::CreateLabel(this);
Result->Caption = Label;
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::AddEditLikeControl(TWinControl * Edit, TLabel * Label, bool OneLine)
{
Edit->Parent = GetDefaultParent();
// this updates Height property to real value
Edit->HandleNeeded();
if (Label != NULL)
{
Label->Parent = GetDefaultParent();
Label->Left = FIndent;
if (OneLine)
{
DebugAssert(Edit->Height > Label->Height);
Label->Top = FPos + ((Edit->Height - Label->Height) / 2);
}
else
{
Label->Top = FPos;
FPos += Label->Height + ScaleByTextHeight(this, 3);
}
}
Edit->Top = FPos;
if (OneLine)
{
Edit->Left = GetDefaultParent()->ClientWidth - FHorizontalMargin - Edit->Width;
}
else
{
Edit->Left = FIndent;
Edit->Width = GetMaxControlWidth(Edit);
}
AdjustHeight(Edit);
if (Label != NULL)
{
if (Label->FocusControl == NULL)
{
Label->FocusControl = Edit;
}
else
{
DebugAssert(Label->FocusControl == Edit);
}
}
AddWinControl(Edit);
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::AddEdit(TCustomEdit * Edit, TLabel * Label, bool OneLine)
{
AddEditLikeControl(Edit, Label, OneLine);
TEdit * PublicEdit = reinterpret_cast<TEdit *>(Edit);
if (PublicEdit->OnChange == NULL)
{
PublicEdit->OnChange = Change;
}
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::SetUpComboBox(TCustomCombo * Combo, TStrings * Items, bool OneLine)
{
if (Items != NULL)
{
Combo->Items = Items;
}
if (OneLine)
{
int Width = 0;
for (int Index = 0; Index < Combo->Items->Count; Index++)
{
Width = Max(Width, Combo->Canvas->TextWidth(Combo->Items->Strings[Index]));
}
Width += ScaleByTextHeight(Combo, 4 + 16 + 14);
Width = Max(Width, HelpButton->Width);
Combo->Width = Width;
Combo->Left = GetDefaultParent()->ClientWidth - FHorizontalMargin - Width;
}
TComboBox * PublicCombo = reinterpret_cast<TComboBox *>(Combo);
if (PublicCombo->OnChange == NULL)
{
PublicCombo->OnChange = Change;
}
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::AddComboBox(TCustomCombo * Combo, TLabel * Label, TStrings * Items, bool OneLine)
{
AddEditLikeControl(Combo, Label, OneLine);
SetUpComboBox(Combo, Items, OneLine);
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::AddShortCutComboBox(TComboBox * Combo, TLabel * Label, const TShortCuts & ShortCuts)
{
AddEditLikeControl(Combo, Label, true);
InitializeShortCutCombo(Combo, ShortCuts);
SetUpComboBox(Combo, NULL, true);
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::ScaleButtonControl(TButtonControl * Control)
{
// this updates Height property to real value
Control->HandleNeeded();
// buttons do not scale with text on their own
Control->Height = ScaleByTextHeight(Control, Control->Height);
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::AddButtonControl(TButtonControl * Control)
{
Control->Parent = GetDefaultParent();
Control->Left = FIndent + ScaleByTextHeight(this, 2);
Control->Top = FPos;
Control->Width = GetMaxControlWidth(Control);
ScaleButtonControl(Control);
AdjustHeight(Control);
AddWinControl(Control);
TCheckBox * PublicControl = reinterpret_cast<TCheckBox *>(Control);
if (PublicControl->OnClick == NULL)
{
PublicControl->OnClick = Change;
}
}
//---------------------------------------------------------------------------
void TCustomDialog::AddButtonNextToEdit(TButton * Button, TWinControl * Edit)
{
Button->Parent = GetDefaultParent();
Button->Width = HelpButton->Width;
Button->Left = GetDefaultParent()->ClientWidth - Button->Width - HorizontalMargin;
Edit->Width = Button->Left - Edit->Left - ScaleByTextHeight(this, 6);
Button->Top = Edit->Top - ScaleByTextHeight(this, 1);
ScaleButtonControl(Button);
AddWinControl(Button);
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::AddText(TLabel * Label)
{
Label->Parent = GetDefaultParent();
DebugAssert(Label->AutoSize);
Label->WordWrap = true;
Label->Left = FIndent;
Label->Width = GetMaxControlWidth(Label);
Label->Top = FPos;
Label->ShowAccelChar = false;
AutoSizeLabel(Label);
AdjustHeight(Label);
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::AddText(TStaticText * Label)
{
Label->Parent = GetDefaultParent();
DebugAssert(Label->AutoSize);
Label->Left = FIndent;
Label->Top = FPos;
Label->ShowAccelChar = false;
AdjustHeight(Label);
AddWinControl(Label);
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::AddSeparator()
{
TBevel * Bevel = new TBevel(this);
Bevel->Parent = GetDefaultParent();
Bevel->Left = FIndent;
Bevel->Top = FPos;
Bevel->Height = 2;
Bevel->Width = GetMaxControlWidth(Bevel);
AdjustHeight(Bevel);
}
//---------------------------------------------------------------------------
void __fastcall TCustomDialog::StartGroup(const UnicodeString & Caption)
{
if (FGroupBox != NULL)
{
FIndent = FGroupBox->Left;
FPos = FGroupBox->Top + FGroupBox->Height + FControlPadding;
FPrePos = FPos;
FGroupBox = NULL;
}
TGroupBox * GroupBox = new TGroupBox(this);
GroupBox->Parent = this;
GroupBox->Caption = Caption;
GroupBox->Left = FIndent;
GroupBox->Top = FPos;
GroupBox->Height = ScaleByTextHeight(GroupBox, 26);
GroupBox->Width = GetMaxControlWidth(GroupBox);
AdjustHeight(GroupBox);
AddWinControl(GroupBox);
// but if the first control is oneline box, then we should roll back a bit
FPos = ScaleByTextHeight(this, 22);
FPrePos = FPos;
FIndent = FHorizontalMargin + GroupBoxBorderWidth;
FGroupBox = GroupBox;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
class TSaveSessionDialog : public TCustomDialog
{
public:
__fastcall TSaveSessionDialog(TComponent* AOwner);
void __fastcall Init(bool CanSavePassword, bool NotRecommendedSavingPassword,
TStrings * AdditionalFolders);
bool __fastcall Execute(UnicodeString & SessionName, bool & SavePassword,
bool & CreateShortcut, const UnicodeString & OriginalSessionName);
protected:
virtual void __fastcall DoValidate();
virtual void __fastcall DoChange(bool & CanSubmit);
private:
UnicodeString FOriginalSessionName;
TEdit * SessionNameEdit;
TComboBox * FolderCombo;
TCheckBox * SavePasswordCheck;
TCheckBox * CreateShortcutCheck;
UnicodeString FRootFolder;
UnicodeString __fastcall GetSessionName();
};
//---------------------------------------------------------------------------
// Need to have an Owner argument for SafeFormCreate
__fastcall TSaveSessionDialog::TSaveSessionDialog(TComponent* /*AOwner*/) :
TCustomDialog(HELP_SESSION_SAVE)
{
}
//---------------------------------------------------------------------------
void __fastcall TSaveSessionDialog::Init(bool CanSavePassword,
bool NotRecommendedSavingPassword, TStrings * AdditionalFolders)
{
Caption = LoadStr(SAVE_SESSION_CAPTION);
SessionNameEdit = new TEdit(this);
AddEdit(SessionNameEdit, CreateLabel(LoadStr(SAVE_SESSION_PROMPT)));
FRootFolder = LoadStr(SAVE_SESSION_ROOT_FOLDER2);
std::unique_ptr<TStringList> Folders(new TStringList());
if (AdditionalFolders != NULL)
{
Folders->AddStrings(AdditionalFolders);
}
for (int Index = 0; Index < StoredSessions->Count; Index++)
{
TSessionData * Data = StoredSessions->Sessions[Index];
if (!Data->Special && !Data->IsWorkspace)
{
UnicodeString Folder = Data->FolderName;
if (!Folder.IsEmpty() && Folders->IndexOf(Folder) < 0)
{
Folders->Add(Folder);
}
}
}
DebugAssert(!Folders->CaseSensitive);
Folders->Sort();
FolderCombo = new TUIStateAwareComboBox(this);
AddComboBox(FolderCombo, CreateLabel(LoadStr(SAVE_SESSION_FOLDER)));
FolderCombo->DropDownCount = Max(FolderCombo->DropDownCount, 16);
FolderCombo->Items->Add(FRootFolder);
FolderCombo->Items->AddStrings(Folders.get());
SavePasswordCheck = CreateAndAddCheckBox(
LoadStr(NotRecommendedSavingPassword ? SAVE_SESSION_PASSWORD :
(CustomWinConfiguration->UseMasterPassword ? SAVE_SESSION_PASSWORD_MASTER : SAVE_SESSION_PASSWORD_RECOMMENDED)));
CreateShortcutCheck = CreateAndAddCheckBox(LoadStr(SAVE_SITE_WORKSPACE_SHORTCUT));
EnableControl(SavePasswordCheck, CanSavePassword);
}
//---------------------------------------------------------------------------
bool __fastcall TSaveSessionDialog::Execute(
UnicodeString & SessionName, bool & SavePassword, bool & CreateShortcut,
const UnicodeString & OriginalSessionName)
{
FOriginalSessionName = OriginalSessionName;
SessionNameEdit->Text = TSessionData::ExtractLocalName(SessionName);
UnicodeString Folder = TSessionData::ExtractFolderName(SessionName);
if (Folder.IsEmpty())
{
FolderCombo->Text = FRootFolder;
}
else
{
FolderCombo->Text = Folder;
}
SavePasswordCheck->Checked = SavePassword;
CreateShortcutCheck->Checked = CreateShortcut;
bool Result = TCustomDialog::Execute();
if (Result)
{
SessionName = GetSessionName();
SavePassword = SavePasswordCheck->Checked;
CreateShortcut = CreateShortcutCheck->Checked;
}
return Result;
}
//---------------------------------------------------------------------------
UnicodeString __fastcall TSaveSessionDialog::GetSessionName()
{
UnicodeString Folder;
if (FolderCombo->Text != FRootFolder)
{
Folder = FolderCombo->Text;
}
return TSessionData::ComposePath(Folder, SessionNameEdit->Text);
}
//---------------------------------------------------------------------------
void __fastcall TSaveSessionDialog::DoValidate()
{
TSessionData::ValidateName(SessionNameEdit->Text);
SessionNameValidate(GetSessionName(), FOriginalSessionName);
UnicodeString Folder = TSessionData::ExtractFolderName(GetSessionName());
if (!Folder.IsEmpty() && StoredSessions->IsWorkspace(Folder))
{
throw Exception(FMTLOAD(WORKSPACE_NOT_FOLDER, (Folder)));
}
if (SavePasswordCheck->Enabled && SavePasswordCheck->Checked &&
CustomWinConfiguration->UseMasterPassword)
{
CustomWinConfiguration->AskForMasterPasswordIfNotSet();
}
TCustomDialog::DoValidate();
}
//---------------------------------------------------------------------------
void __fastcall TSaveSessionDialog::DoChange(bool & CanSubmit)
{
CanSubmit = !SessionNameEdit->Text.IsEmpty();
TCustomDialog::DoChange(CanSubmit);
}
//---------------------------------------------------------------------------
TSessionData * __fastcall DoSaveSession(TSessionData * SessionData,
TSessionData * OriginalSession, bool ForceDialog,
TStrings * AdditionalFolders)
{
bool SavePassword = false;
bool * PSavePassword;
bool NotRecommendedSavingPassword =
!CustomWinConfiguration->UseMasterPassword &&
!SameText(SessionData->UserName, AnonymousUserName);
if (Configuration->DisablePasswordStoring ||
!SessionData->HasAnySessionPassword())
{
PSavePassword = NULL;
}
else
{
PSavePassword = &SavePassword;
SavePassword =
((OriginalSession != NULL) && OriginalSession->HasAnySessionPassword()) ||
!NotRecommendedSavingPassword;
}
UnicodeString SessionName = SessionData->SessionName;
bool Result;
bool CreateShortcut = false;
if (!ForceDialog && ((PSavePassword == NULL) || SavePassword))
{
// This is probably here to ask before session is started saving.
// Otherwise we would ask implicitly, when saving passwords, but at that moment,
// part of the site is already saved and when the user cancel the prompt it's too late.
CustomWinConfiguration->AskForMasterPasswordIfNotSetAndNeededToPersistSessionData(SessionData);
Result = true;
}
else
{
// This can be a standalone dialog when used with save URL (from GetLoginData)
TSaveSessionDialog * Dialog = SafeFormCreate<TSaveSessionDialog>();
try
{
Dialog->Init((PSavePassword != NULL), NotRecommendedSavingPassword, AdditionalFolders);
Result = Dialog->Execute(SessionName, SavePassword, CreateShortcut, SessionData->Name);
}
__finally
{
delete Dialog;
}
}
TSessionData * NewSession = NULL;
if (Result)
{
if ((PSavePassword != NULL) && !SavePassword)
{
SessionData->ClearSessionPasswords();
}
NewSession =
StoredSessions->NewSession(SessionName, SessionData);
// modified only, explicit
StoredSessions->Save(false, true);
if (!SessionData->HostKey.IsEmpty())
{
SessionData->CacheHostKeyIfNotCached();
}
if (CreateShortcut)
{
TOperationVisualizer Visualizer;
UnicodeString AdditionalParams =
TProgramParams::FormatSwitch(DESKTOP_SWITCH) + L" " +
TProgramParams::FormatSwitch(UPLOAD_IF_ANY_SWITCH);
CreateDesktopSessionShortCut(SessionName, L"", AdditionalParams, -1, SITE_ICON);
}
}
return NewSession;
}
//---------------------------------------------------------------------------
void __fastcall SessionNameValidate(const UnicodeString & Text,
const UnicodeString & OriginalName)
{
TSessionData::ValidatePath(Text);
DebugAssert(StoredSessions);
TSessionData * Data = (TSessionData *)StoredSessions->FindByName(Text);
if (Data && Data->Special)
{
MessageDialog(FMTLOAD(CANNOT_OVERWRITE_SPECIAL_SESSION, (Text)),
qtError, qaOK, HELP_NONE);
Abort();
}
else if ((Data != NULL) && !Data->IsSameName(OriginalName) &&
MessageDialog(MainInstructions(FMTLOAD(CONFIRM_OVERWRITE_SESSION, (Text))),
qtConfirmation, qaYes | qaNo, HELP_SESSION_SAVE_OVERWRITE) != qaYes)
{
Abort();
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
class TSaveWorkspaceDialog : public TCustomDialog
{
public:
__fastcall TSaveWorkspaceDialog(bool CanSavePasswords,
bool NotRecommendedSavingPasswords);
bool __fastcall Execute(
UnicodeString & WorkspaceName, bool & SavePasswords, bool & CreateShortcut,
bool & EnableAutoSave);
protected:
virtual void __fastcall DoValidate();
virtual void __fastcall DoChange(bool & CanSubmit);
private:
TComboBox * WorkspaceNameCombo;
TCheckBox * SavePasswordsCheck;
TCheckBox * CreateShortcutCheck;
TCheckBox * EnableAutoSaveCheck;
};
//---------------------------------------------------------------------------
__fastcall TSaveWorkspaceDialog::TSaveWorkspaceDialog(
bool CanSavePasswords, bool NotRecommendedSavingPasswords) :
TCustomDialog(HELP_WORKSPACE_SAVE)
{
Caption = LoadStr(SAVE_WORKSPACE_CAPTION);
WorkspaceNameCombo = new TUIStateAwareComboBox(this);
WorkspaceNameCombo->AutoComplete = false;
AddComboBox(WorkspaceNameCombo, CreateLabel(LoadStr(SAVE_WORKSPACE_PROMPT)));
WorkspaceNameCombo->DropDownCount = Max(WorkspaceNameCombo->DropDownCount, 16);
std::unique_ptr<TStrings> Workspaces(StoredSessions->GetWorkspaces());
WorkspaceNameCombo->Items->AddStrings(Workspaces.get());
SavePasswordsCheck = CreateAndAddCheckBox(
LoadStr(NotRecommendedSavingPasswords ? SAVE_WORKSPACE_PASSWORDS :
(CustomWinConfiguration->UseMasterPassword ?
SAVE_WORKSPACE_PASSWORDS_MASTER : SAVE_WORKSPACE_PASSWORDS_RECOMMENDED)));
EnableControl(SavePasswordsCheck, CanSavePasswords);
CreateShortcutCheck = CreateAndAddCheckBox(LoadStr(SAVE_SITE_WORKSPACE_SHORTCUT));
EnableAutoSaveCheck = CreateAndAddCheckBox(LoadStr(SAVE_WORKSPACE_AUTO));
}
//---------------------------------------------------------------------------
bool __fastcall TSaveWorkspaceDialog::Execute(
UnicodeString & WorkspaceName, bool & SavePasswords, bool & CreateShortcut,
bool & EnableAutoSave)
{
WorkspaceNameCombo->Text = WorkspaceName;
SavePasswordsCheck->Checked = SavePasswords;
CreateShortcutCheck->Checked = CreateShortcut;
EnableAutoSaveCheck->Checked = EnableAutoSave;
bool Result = TCustomDialog::Execute();
if (Result)
{
WorkspaceName = WorkspaceNameCombo->Text;
SavePasswords = SavePasswordsCheck->Checked;
CreateShortcut = CreateShortcutCheck->Checked;
EnableAutoSave = EnableAutoSaveCheck->Checked;
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TSaveWorkspaceDialog::DoValidate()
{
TSessionData::ValidateName(WorkspaceNameCombo->Text);
if (StoredSessions->IsFolder(WorkspaceNameCombo->Text))
{
throw Exception(FMTLOAD(FOLDER_NOT_WORKSPACE, (WorkspaceNameCombo->Text)));
}
if (SavePasswordsCheck->Enabled && SavePasswordsCheck->Checked &&
CustomWinConfiguration->UseMasterPassword)
{
CustomWinConfiguration->AskForMasterPasswordIfNotSet();
}
TCustomDialog::DoValidate();
}
//---------------------------------------------------------------------------
void __fastcall TSaveWorkspaceDialog::DoChange(bool & CanSubmit)
{
CanSubmit = !WorkspaceNameCombo->Text.IsEmpty();
TCustomDialog::DoChange(CanSubmit);
}
//---------------------------------------------------------------------------
bool __fastcall DoSaveWorkspaceDialog(UnicodeString & WorkspaceName,
bool * SavePasswords, bool NotRecommendedSavingPasswords,
bool & CreateShortcut, bool & EnableAutoSave)
{
std::unique_ptr<TSaveWorkspaceDialog> Dialog(
new TSaveWorkspaceDialog((SavePasswords != NULL), NotRecommendedSavingPasswords));
bool Dummy = false;
if (SavePasswords == NULL)
{
SavePasswords = &Dummy;
}
return
Dialog->Execute(
WorkspaceName, *SavePasswords, CreateShortcut, EnableAutoSave);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
class TShortCutDialog : public TCustomDialog
{
public:
__fastcall TShortCutDialog(const TShortCuts & ShortCuts, UnicodeString HelpKeyword);
bool __fastcall Execute(TShortCut & ShortCut);
private:
TComboBox * ShortCutCombo;
};
//---------------------------------------------------------------------------
__fastcall TShortCutDialog::TShortCutDialog(const TShortCuts & ShortCuts, UnicodeString HelpKeyword) :
TCustomDialog(HelpKeyword)
{
Caption = LoadStr(SHORTCUT_CAPTION);
ShortCutCombo = new TUIStateAwareComboBox(this);
AddShortCutComboBox(ShortCutCombo, CreateLabel(LoadStr(SHORTCUT_LABEL)), ShortCuts);
}
//---------------------------------------------------------------------------
bool __fastcall TShortCutDialog::Execute(TShortCut & ShortCut)
{
SetShortCutCombo(ShortCutCombo, ShortCut);
bool Result = TCustomDialog::Execute();
if (Result)
{
ShortCut = GetShortCutCombo(ShortCutCombo);
}
return Result;
}
//---------------------------------------------------------------------------
bool __fastcall DoShortCutDialog(TShortCut & ShortCut,
const TShortCuts & ShortCuts, UnicodeString HelpKeyword)
{
bool Result;
TShortCutDialog * Dialog = new TShortCutDialog(ShortCuts, HelpKeyword);
try
{
Result = Dialog->Execute(ShortCut);
}
__finally
{
delete Dialog;
}
return Result;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
class TRemoteMoveDialog : public TCustomDialog
{
public:
__fastcall TRemoteMoveDialog(bool Multi, TDirectoryExistsEvent OnDirectoryExists);
bool __fastcall Execute(UnicodeString & Target, UnicodeString & FileMask);
protected:
DYNAMIC void __fastcall DoShow();
virtual void __fastcall DoValidate();
UnicodeString __fastcall GetFileMask();
private:
THistoryComboBox * Combo;
bool FMulti;
TDirectoryExistsEvent FOnDirectoryExists;
};
//---------------------------------------------------------------------------
__fastcall TRemoteMoveDialog::TRemoteMoveDialog(bool Multi, TDirectoryExistsEvent OnDirectoryExists) :
TCustomDialog(HELP_REMOTE_MOVE)
{
Caption = LoadStr(REMOTE_MOVE_TITLE);
// The same as TRemoteTransferDialog
ClientWidth = ScaleByTextHeight(this, 466);
FMulti = Multi;
FOnDirectoryExists = OnDirectoryExists;
AddImage(L"Move L to R");
Combo = new THistoryComboBox(this);
Combo->AutoComplete = false;
AddComboBox(Combo, CreateLabel(LoadStr(REMOTE_TRANSFER_PROMPT2)));
}
//---------------------------------------------------------------------------
bool __fastcall TRemoteMoveDialog::Execute(UnicodeString & Target, UnicodeString & FileMask)
{
Combo->Items = CustomWinConfiguration->History[L"RemoteTarget"];
Combo->Text = UnixIncludeTrailingBackslash(Target) + FileMask;
bool Result = TCustomDialog::Execute();
if (Result)
{
Target = UnixExtractFilePath(Combo->Text);
FileMask = GetFileMask();
Combo->SaveToHistory();
CustomWinConfiguration->History[L"RemoteTarget"] = Combo->Items;
}
return Result;
}
//---------------------------------------------------------------------------
UnicodeString __fastcall TRemoteMoveDialog::GetFileMask()
{
return UnixExtractFileName(Combo->Text);
}
//---------------------------------------------------------------------------
void __fastcall TRemoteMoveDialog::DoShow()
{
TCustomDialog::DoShow();
InstallPathWordBreakProc(Combo);
}
//---------------------------------------------------------------------------
void __fastcall TRemoteMoveDialog::DoValidate()
{
if (FOnDirectoryExists(NULL, Combo->Text))
{
Combo->Text = UnixCombinePaths(Combo->Text, AnyMask);
}
if (!IsFileNameMask(GetFileMask()) && FMulti)
{
UnicodeString Message =
FormatMultiFilesToOneConfirmation(Combo->Text, true);
if (MessageDialog(Message, qtConfirmation, qaOK | qaCancel, HELP_NONE) == qaCancel)
{
Abort();
}
}
TCustomDialog::DoValidate();
}
//---------------------------------------------------------------------------
bool __fastcall DoRemoteMoveDialog(
bool Multi, UnicodeString & Target, UnicodeString & FileMask, TDirectoryExistsEvent OnDirectoryExists)
{
std::unique_ptr<TRemoteMoveDialog> Dialog(new TRemoteMoveDialog(Multi, OnDirectoryExists));
return Dialog->Execute(Target, FileMask);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
class TCustomCommandOptionsDialog : public TCustomDialog
{
public:
__fastcall TCustomCommandOptionsDialog(
const TCustomCommandType * Command, TStrings * CustomCommandOptions, unsigned int Flags,
TCustomCommand * CustomCommandForOptions, const UnicodeString & Site, const TShortCuts * ShortCuts);
bool __fastcall Execute(TShortCut * ShortCut);
protected:
virtual void __fastcall DoHelp();
DYNAMIC void __fastcall DoShow();
private:
const TCustomCommandType * FCommand;
TStrings * FCustomCommandOptions;
std::vector<TControl *> FControls;
std::vector<std::vector<UnicodeString> > FValues;
unsigned int FFlags;
UnicodeString FSite;
TComboBox * FShortCutCombo;
UnicodeString __fastcall HistoryKey(const TCustomCommandType::TOption & Option);
THistoryComboBox * __fastcall CreateHistoryComboBox(const TCustomCommandType::TOption & Option, const UnicodeString & Value);
void __fastcall BrowseButtonClick(TObject * Sender);
void __fastcall LinkLabelClick(TObject * Sender);
UnicodeString __fastcall SaveHistoryComboBoxValue(TControl * Control, const TCustomCommandType::TOption & Option);
void __fastcall AddOptionComboBox(
TComboBox * ComboBox, const UnicodeString & Value, const TCustomCommandType::TOption & Option,
std::vector<UnicodeString> & Values);
UnicodeString __fastcall GetComboBoxValue(TControl * Control, const UnicodeString & Default);
int __fastcall GetOptionIndex(TControl * Control);
int __fastcall GetControlIndex(TControl * Control);
};
//---------------------------------------------------------------------------
__fastcall TCustomCommandOptionsDialog::TCustomCommandOptionsDialog(
const TCustomCommandType * Command, TStrings * CustomCommandOptions,
unsigned int Flags, TCustomCommand * CustomCommandForOptions,
const UnicodeString & Site, const TShortCuts * ShortCuts) :
TCustomDialog(HELP_EXTENSION_OPTIONS)
{
FCommand = Command;
FFlags = Flags;
FCustomCommandOptions = CustomCommandOptions;
FSite = Site;
Caption = StripEllipsis(StripHotkey(FCommand->Name));
Width = ScaleByTextHeight(this, 444);
bool HasGroups = false;
int ControlIndex = 0;
for (int OptionIndex = 0; OptionIndex < FCommand->OptionsCount; OptionIndex++)
{
const TCustomCommandType::TOption & Option = FCommand->GetOption(OptionIndex);
if ((Option.Flags & FFlags) != 0)
{
UnicodeString OptionKey = FCommand->GetOptionKey(Option, FSite);
UnicodeString Value;
if ((CustomCommandForOptions != NULL) &&
Option.HasPatterns(CustomCommandForOptions))
{
Value = CustomCommandForOptions->Complete(Option.Default, true);
}
else
{
if (FCustomCommandOptions->IndexOfName(OptionKey) >= 0)
{
Value = FCustomCommandOptions->Values[OptionKey];
}
else
{
Value = Option.Default;
}
}
int Tag = (OptionIndex << 16) + ControlIndex;
TControl * Control = NULL;
std::vector<UnicodeString> Values;
if (Option.Kind == TCustomCommandType::okUnknown)
{
Control = NULL;
}
else if (Option.Kind == TCustomCommandType::okLabel)
{
TLabel * Label = CreateLabel(Option.Caption);
AddText(Label);
Control = Label;
}
else if (Option.Kind == TCustomCommandType::okLink)
{
TStaticText * Label = new TStaticText(this);
Label->Caption = Option.Caption;
if (IsHttpOrHttpsUrl(Label->Caption))
{
Label->Caption = SecureUrl(Label->Caption);
LinkLabel(Label);
Label->TabStop = true;
}
else if (!Option.Default.IsEmpty() && IsHttpOrHttpsUrl(Option.Default))
{
Label->OnClick = LinkLabelClick;
LinkLabel(Label);
Label->TabStop = true;
}
else
{
// keep it plain text, as we have no URL
}
AddText(Label);
Control = Label;
}
else if (Option.Kind == TCustomCommandType::okGroup)
{
StartGroup(Option.Caption);
HasGroups = true;
}
else if (Option.Kind == TCustomCommandType::okSeparator)
{
AddSeparator();
}
else if (Option.Kind == TCustomCommandType::okTextBox)
{
Control = CreateHistoryComboBox(Option, Value);
}
else if (Option.Kind == TCustomCommandType::okFile)
{
THistoryComboBox * ComboBox = CreateHistoryComboBox(Option, Value);
TButton * Button = CreateButton(this);
AddButtonNextToEdit(Button, ComboBox);
Button->Tag = Tag;
Button->Caption = LoadStr(EXTENSION_OPTIONS_BROWSE);
Button->OnClick = BrowseButtonClick;
Control = ComboBox;
}
else if (Option.Kind == TCustomCommandType::okDropDownList)
{
TComboBox * ComboBox = new TUIStateAwareComboBox(this);
ComboBox->Style = csDropDownList;
AddOptionComboBox(ComboBox, Value, Option, Values);
Control = ComboBox;
}
else if (Option.Kind == TCustomCommandType::okComboBox)
{
TComboBox * ComboBox = new TUIStateAwareComboBox(this);
ComboBox->Style = csDropDown;
AddOptionComboBox(ComboBox, Value, Option, Values);
if (ComboBox->ItemIndex < 0)
{
ComboBox->Text = Value;
}
Control = ComboBox;
}
else if (Option.Kind == TCustomCommandType::okCheckBox)
{
TCheckBox * CheckBox = CreateAndAddCheckBox(Option.Caption);
CheckBox->Checked =
(Option.Params.size() >= 1) &&
(Value == Option.Params[0]);
Control = CheckBox;
}
else
{
DebugFail();
}
if (Control != NULL)
{
Control->Tag = Tag;
}
FControls.push_back(Control);
FValues.push_back(Values);
ControlIndex++;
DebugAssert(static_cast<int>(FControls.size()) == ControlIndex);
}
}
if (ShortCuts != NULL)
{
if (HasGroups)
{
StartGroup(LoadStr(EXTENSION_GENERAL_GROUP));
}
else if (ControlIndex > 0)
{
AddSeparator();
}
FShortCutCombo = new TUIStateAwareComboBox(this);
AddShortCutComboBox(FShortCutCombo, CreateLabel(LoadStr(EXTENSION_SHORTCUT)), *ShortCuts);
}
}
//---------------------------------------------------------------------------
void __fastcall TCustomCommandOptionsDialog::AddOptionComboBox(
TComboBox * ComboBox, const UnicodeString & Value, const TCustomCommandType::TOption & Option, std::vector<UnicodeString> & Values)
{
std::unique_ptr<TStringList> Items(new TStringList());
int ItemIndex = -1;
TCustomCommandType::TOption::TParams::const_iterator ParamI = Option.Params.begin();
while (ParamI != Option.Params.end())
{
UnicodeString Item = (*ParamI);
int P = Item.Pos(L"=");
UnicodeString ParamValue;
if (P > 0)
{
ParamValue = Item.SubString(1, P - 1);
Item.Delete(1, P);
}
else
{
ParamValue = Item;
}
Item = WinConfiguration->ExtensionStringTranslation(FCommand->Id, Item);
Items->Add(Item);
if (Value == ParamValue)
{
ItemIndex = Items->Count - 1;
}
Values.push_back(ParamValue);
ParamI++;
}
AddComboBox(ComboBox, CreateLabel(Option.Caption), Items.get(), true);
ComboBox->ItemIndex = ItemIndex;
}
//---------------------------------------------------------------------------
int __fastcall TCustomCommandOptionsDialog::GetOptionIndex(TControl * Control)
{
return (Control->Tag >> 16);
}
//---------------------------------------------------------------------------
int __fastcall TCustomCommandOptionsDialog::GetControlIndex(TControl * Control)
{
return (Control->Tag & 0xFFFF);
}
//---------------------------------------------------------------------------
void __fastcall TCustomCommandOptionsDialog::LinkLabelClick(TObject * Sender)
{
TStaticText * Label = DebugNotNull(dynamic_cast<TStaticText *>(Sender));
const TCustomCommandType::TOption & Option = FCommand->GetOption(GetOptionIndex(Label));
OpenBrowser(SecureUrl(Option.Default));
}
//---------------------------------------------------------------------------
void __fastcall TCustomCommandOptionsDialog::BrowseButtonClick(TObject * Sender)
{
TButton * Button = DebugNotNull(dynamic_cast<TButton *>(Sender));
int OptionIndex = GetOptionIndex(Button);
const TCustomCommandType::TOption & Option = FCommand->GetOption(OptionIndex);
int ControlIndex = GetControlIndex(Button);
THistoryComboBox * ComboBox = dynamic_cast<THistoryComboBox *>(FControls[ControlIndex]);
std::unique_ptr<TOpenDialog> OpenDialog(new TOpenDialog(Application));
UnicodeString Title;
if (!Option.FileCaption.IsEmpty())
{
Title = Option.FileCaption;
}
else
{
UnicodeString Caption = Option.Caption;
Caption = StripHotkey(Caption);
if (!Caption.IsEmpty() && (Caption[Caption.Length()] == L':'))
{
Caption.SetLength(Caption.Length() - 1);
}
Title = FMTLOAD(EXTENSION_OPTIONS_BROWSE_TITLE, (Caption));
}
OpenDialog->Title = Title;
UnicodeString Value;
if (ComboBox->Text.IsEmpty())
{
Value = Option.FileInitial;
}
else
{
Value = ComboBox->Text;
}
UnicodeString ExpandedValue = ExpandEnvironmentVariables(Value);
OpenDialog->FileName = ExpandedValue;
UnicodeString InitialDir = ExtractFilePath(ExpandedValue);
if (!InitialDir.IsEmpty())
{
OpenDialog->InitialDir = InitialDir;
}
OpenDialog->Filter = Option.FileFilter;
OpenDialog->DefaultExt = Option.FileExt;
if (OpenDialog->Execute())
{
if (OpenDialog->FileName != ExpandedValue)
{
ComboBox->Text = OpenDialog->FileName;
}
// If user just confirms the initial value, persist it
else if (ComboBox->Text.IsEmpty())
{
DebugAssert(Option.FileInitial == Value);
ComboBox->Text = Value;
}
}
}
//---------------------------------------------------------------------------
THistoryComboBox * __fastcall TCustomCommandOptionsDialog::CreateHistoryComboBox(
const TCustomCommandType::TOption & Option, const UnicodeString & Value)
{
THistoryComboBox * ComboBox = new THistoryComboBox(this);
ComboBox->AutoComplete = false;
AddComboBox(ComboBox, CreateLabel(Option.Caption));
ComboBox->Items = CustomWinConfiguration->History[HistoryKey(Option)];
ComboBox->Text = Value;
return ComboBox;
}
//---------------------------------------------------------------------------
UnicodeString __fastcall TCustomCommandOptionsDialog::HistoryKey(const TCustomCommandType::TOption & Option)
{
UnicodeString Result = FCommand->GetOptionKey(Option, FSite);
Result = CustomWinConfiguration->GetValidHistoryKey(Result);
return L"CustomCommandOption_" + Result;
}
//---------------------------------------------------------------------------
bool __fastcall TCustomCommandOptionsDialog::Execute(TShortCut * ShortCut)
{
if (ShortCut != NULL)
{
SetShortCutCombo(FShortCutCombo, *ShortCut);
}
bool Result = TCustomDialog::Execute();
if (Result)
{
int ControlIndex = 0;
for (int OptionIndex = 0; OptionIndex < FCommand->OptionsCount; OptionIndex++)
{
const TCustomCommandType::TOption & Option = FCommand->GetOption(OptionIndex);
if ((Option.Flags & FFlags) != 0)
{
if ((Option.Kind != TCustomCommandType::okUnknown) &&
Option.IsControl)
{
UnicodeString OptionKey = FCommand->GetOptionKey(Option, FSite);
TControl * Control = FControls[ControlIndex];
UnicodeString Value;
if (Option.Kind == TCustomCommandType::okTextBox)
{
Value = SaveHistoryComboBoxValue(Control, Option);
}
else if (Option.Kind == TCustomCommandType::okFile)
{
Value = SaveHistoryComboBoxValue(Control, Option);
}
else if (Option.Kind == TCustomCommandType::okDropDownList)
{
Value = GetComboBoxValue(Control, Option.Default);
}
else if (Option.Kind == TCustomCommandType::okComboBox)
{
TComboBox * ComboBox = DebugNotNull(dynamic_cast<TComboBox *>(Control));
Value = GetComboBoxValue(Control, ComboBox->Text);
}
else if (Option.Kind == TCustomCommandType::okCheckBox)
{
TCheckBox * CheckBox = DebugNotNull(dynamic_cast<TCheckBox *>(Control));
int Index = (CheckBox->Checked ? 0 : 1);
Value = (Index < static_cast<int>(Option.Params.size())) ? Option.Params[Index] : UnicodeString();
}
else
{
DebugFail();
}
// The default value setter deletes the "name" when the value is empty.
// It would cause us to fall back to the default value, but we want to remember the empty value.
SetStringValueEvenIfEmpty(FCustomCommandOptions, OptionKey, Value);
}
ControlIndex++;
}
}
if (ShortCut != NULL)
{
*ShortCut = GetShortCutCombo(FShortCutCombo);
}
}
return Result;
}
//---------------------------------------------------------------------------
UnicodeString __fastcall TCustomCommandOptionsDialog::GetComboBoxValue(
TControl * Control, const UnicodeString & Default)
{
TComboBox * ComboBox = DebugNotNull(dynamic_cast<TComboBox *>(Control));
UnicodeString Result;
if (ComboBox->ItemIndex < 0)
{
Result = Default;
}
else
{
Result = FValues[GetControlIndex(Control)][ComboBox->ItemIndex];
}
return Result;
}
//---------------------------------------------------------------------------
UnicodeString __fastcall TCustomCommandOptionsDialog::SaveHistoryComboBoxValue(
TControl * Control, const TCustomCommandType::TOption & Option)
{
THistoryComboBox * ComboBox = DebugNotNull(dynamic_cast<THistoryComboBox *>(Control));
ComboBox->SaveToHistory();
CustomWinConfiguration->History[HistoryKey(Option)] = ComboBox->Items;
return ComboBox->Text;
}
//---------------------------------------------------------------------------
void __fastcall TCustomCommandOptionsDialog::DoHelp()
{
UnicodeString HelpPage;
if (!FCommand->OptionsPage.IsEmpty())
{
HelpPage = FCommand->OptionsPage;
}
else
{
HelpPage = FCommand->HomePage;
}
if (!HelpPage.IsEmpty())
{
OpenBrowser(HelpPage);
}
else
{
TCustomDialog::DoHelp();
}
}
//---------------------------------------------------------------------------
void __fastcall TCustomCommandOptionsDialog::DoShow()
{
TCustomDialog::DoShow();
int ControlIndex = 0;
for (int OptionIndex = 0; OptionIndex < FCommand->OptionsCount; OptionIndex++)
{
const TCustomCommandType::TOption & Option = FCommand->GetOption(OptionIndex);
if ((Option.Flags & FFlags) != 0)
{
if (Option.Kind == TCustomCommandType::okFile)
{
TControl * Control = FControls[ControlIndex];
InstallPathWordBreakProc(DebugNotNull(dynamic_cast<TWinControl *>(Control)));
}
ControlIndex++;
}
}
}
//---------------------------------------------------------------------------
bool __fastcall DoCustomCommandOptionsDialog(
const TCustomCommandType * Command, TStrings * CustomCommandOptions, TShortCut * ShortCut,
unsigned int Flags, TCustomCommand * CustomCommandForOptions,
const UnicodeString & Site, const TShortCuts * ShortCuts)
{
std::unique_ptr<TCustomCommandOptionsDialog> Dialog(
new TCustomCommandOptionsDialog(Command, CustomCommandOptions, Flags, CustomCommandForOptions, Site, ShortCuts));
return Dialog->Execute(ShortCut);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
class TUsageStatisticsDialog : public TCustomDialog
{
public:
__fastcall TUsageStatisticsDialog();
protected:
virtual void __fastcall DoChange(bool & CanSubmit);
private:
TEdit * FilterEdit;
TMemo * UsageMemo;
TButton * ClipboardButton;
void __fastcall ClipboardButtonClick(TObject * Sender);
};
//---------------------------------------------------------------------------
__fastcall TUsageStatisticsDialog::TUsageStatisticsDialog() :
TCustomDialog(HELP_USAGE)
{
Caption = LoadStr(USAGE_CAPTION);
Width = ScaleByTextHeight(this, 444);
// UnformatMessage is called, because previously, ** markup was used and translations may still contain that
AddText(CreateLabel(UnformatMessage(LoadStr(USAGE_DATA2))));
FilterEdit = new TEdit(this);
FilterEdit->Width = ScaleByTextHeight(this, 277);
AddEdit(FilterEdit, CreateLabel(LoadStr(USAGE_FILTER)), true);
UsageMemo = new TMemo(this);
UsageMemo->Height = ScaleByTextHeight(this, 333);
UsageMemo->ScrollBars = ssVertical;
AddEdit(UsageMemo, NULL);
ReadOnlyControl(UsageMemo);
ClipboardButton = CreateButton(this);
ClipboardButton->Caption = LoadStr(USAGE_COPY);
ClipboardButton->Width = ScaleByTextHeight(this, 179);
ClipboardButton->OnClick = ClipboardButtonClick;
AddDialogButton(ClipboardButton);
RemoveCancelButton();
}
//---------------------------------------------------------------------------
void __fastcall TUsageStatisticsDialog::ClipboardButtonClick(TObject * /*Sender*/)
{
TInstantOperationVisualizer Visualizer;
CopyToClipboard(UsageMemo->Lines);
}
//---------------------------------------------------------------------------
void __fastcall TUsageStatisticsDialog::DoChange(bool & CanSubmit)
{
TCustomDialog::DoChange(CanSubmit);
UnicodeString Text = Configuration->Usage->Serialize(L"\n", FilterEdit->Text);
bool NoUsage = Text.IsEmpty();
ClipboardButton->Enabled = !NoUsage;
if (NoUsage)
{
Text = LoadStr(USAGE_DATA_NONE2);
}
UsageMemo->Lines->Text = Text;
}
//---------------------------------------------------------------------------
void __fastcall DoUsageStatisticsDialog()
{
std::unique_ptr<TUsageStatisticsDialog> Dialog(new TUsageStatisticsDialog());
Dialog->Execute();
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
class TSiteRawDialog : public TCustomDialog
{
public:
__fastcall TSiteRawDialog();
bool __fastcall Execute(TSessionData * Data);
protected:
DYNAMIC void __fastcall DoShow();
private:
TMemo * SettingsMemo;
void __fastcall AddButtonClick(TObject * Sender);
void __fastcall SettingsMemoKeyDown(TObject * Sender, WORD & Key, TShiftState Shift);
void DeleteNames(TStrings * Names, TStrings * Options);
};
//---------------------------------------------------------------------------
__fastcall TSiteRawDialog::TSiteRawDialog() :
TCustomDialog(HELP_SITE_RAW)
{
Caption = LoadStr(SITE_RAW_CAPTION);
Width = ScaleByTextHeight(this, 444);
SettingsMemo = new TMemo(this);
SettingsMemo->Height = ScaleByTextHeight(this, 333);
SettingsMemo->OnKeyDown = SettingsMemoKeyDown;
AddEdit(SettingsMemo, NULL);
TButton * AddButton = CreateButton(this);
AddButton->Caption = LoadStr(SITE_RAW_ADD);
AddButton->Width = OKButton->Width;
AddButton->OnClick = AddButtonClick;
AddDialogButton(AddButton);
}
//---------------------------------------------------------------------------
void __fastcall TSiteRawDialog::DoShow()
{
TCustomDialog::DoShow();
InstallPathWordBreakProc(SettingsMemo);
}
//---------------------------------------------------------------------------
bool __fastcall TSiteRawDialog::Execute(TSessionData * Data)
{
std::unique_ptr<TSessionData> FactoryDefaults(new TSessionData(L""));
std::unique_ptr<TSessionData> RawData(new TSessionData(L""));
RawData->Assign(Data);
// SFTP-only is not reflected by the protocol prefix, we have to use rawsettings for that
if (RawData->FSProtocol != fsSFTPonly)
{
RawData->FSProtocol = FactoryDefaults->FSProtocol;
}
RawData->HostName = FactoryDefaults->HostName;
RawData->PortNumber = FactoryDefaults->PortNumber;
RawData->UserName = FactoryDefaults->UserName;
RawData->Password = FactoryDefaults->Password;
RawData->Ftps = FactoryDefaults->Ftps;
std::unique_ptr<TStrings> Options(RawData->SaveToOptions(FactoryDefaults.get(), false, false));
SettingsMemo->Lines = Options.get();
bool Result = TCustomDialog::Execute();
if (Result)
{
std::unique_ptr<TSessionData> BackupData(new TSessionData(L""));
BackupData->Assign(Data);
Data->DefaultSettings();
Data->FSProtocol = BackupData->FSProtocol;
Data->HostName = BackupData->HostName;
Data->PortNumber = BackupData->PortNumber;
Data->UserName = BackupData->UserName;
Data->Password = BackupData->Password;
Data->Ftps = BackupData->Ftps;
Data->ApplyRawSettings(SettingsMemo->Lines, false);
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TSiteRawDialog::SettingsMemoKeyDown(TObject * Sender, WORD & Key, TShiftState Shift)
{
MemoKeyDown(Sender, Key, Shift);
}
//---------------------------------------------------------------------------
void __fastcall TSiteRawDialog::AddButtonClick(TObject *)
{
std::unique_ptr<TSessionData> FactoryDefaults(new TSessionData(L""));
std::unique_ptr<TSessionData> BasicData(new TSessionData(L""));
BasicData->FSProtocol = TFSProtocol(FactoryDefaults->FSProtocol + 1);
UnicodeString RandomAppendix(L"_");
BasicData->HostName = FactoryDefaults->HostName + RandomAppendix;
BasicData->Ftps = TFtps(FactoryDefaults->Ftps + 1);
BasicData->PortNumber = BasicData->GetDefaultPort() + 1;
BasicData->UserName = FactoryDefaults->UserName + RandomAppendix;
BasicData->Password = FactoryDefaults->Password + RandomAppendix;
std::unique_ptr<TStrings> BasicOptions(BasicData->SaveToOptions(FactoryDefaults.get(), false, false));
std::unique_ptr<TStrings> AllOptions(TSessionData::GetAllOptionNames(false));
std::unique_ptr<TStrings> Names(CreateSortedStringList());
for (int Index = 0; Index < AllOptions->Count; Index++)
{
Names->Add(AllOptions->Names[Index]);
}
DeleteNames(Names.get(), BasicOptions.get());
DeleteNames(Names.get(), SettingsMemo->Lines);
std::unique_ptr<TCustomDialog> AddDialog(new TCustomDialog(HelpKeyword));
AddDialog->Caption = LoadStr(SITE_RAW_ADD_CAPTION);
TComboBox * AddComboBox = new TUIStateAwareComboBox(AddDialog.get());
AddComboBox->Style = csDropDownList;
AddComboBox->DropDownCount = Max(AddComboBox->DropDownCount, 16);
AddDialog->AddComboBox(AddComboBox, CreateLabel(LoadStr(SITE_RAW_ADD_LABEL)), Names.get(), true);
AddComboBox->ItemIndex = 0;
if (AddDialog->Execute())
{
UnicodeString Name = AddComboBox->Items->Strings[AddComboBox->ItemIndex];
UnicodeString Value = AllOptions->Values[Name];
UnicodeString NameAndSeparator = Name + SettingsMemo->Lines->NameValueSeparator;
int Start = (SettingsMemo->Lines->Text + NameAndSeparator).Length();
SettingsMemo->Lines->Add(NameAndSeparator + Value);
SettingsMemo->SetFocus();
SettingsMemo->SelStart = Start;
SettingsMemo->SelLength = Value.Length();
}
}
//---------------------------------------------------------------------------
void TSiteRawDialog::DeleteNames(TStrings * Names, TStrings * Options)
{
for (int Index = 0; Index < Options->Count; Index++)
{
UnicodeString Name = Options->Names[Index];
if (!Name.IsEmpty())
{
int I = Names->IndexOf(Name);
if (I >= 0)
{
Names->Delete(I);
}
}
}
}
//---------------------------------------------------------------------------
void __fastcall DoSiteRawDialog(TSessionData * Data)
{
std::unique_ptr<TSiteRawDialog> Dialog(new TSiteRawDialog());
Dialog->Execute(Data);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
class TSshHostCADialog : public TCustomDialog
{
public:
TSshHostCADialog(bool Add);
bool Execute(TSshHostCA & SshHostCA);
protected:
virtual void __fastcall DoChange(bool & CanSubmit);
virtual void __fastcall DoValidate();
private:
TEdit * NameEdit;
TEdit * PublicKeyEdit;
TEdit * PublicKeyLabel;
TEdit * ValidityExpressionEdit;
TCheckBox * PermitRsaSha1Check;
TCheckBox * PermitRsaSha256Check;
TCheckBox * PermitRsaSha512Check;
void __fastcall BrowseButtonClick(TObject * Sender);
TCheckBox * AddValidityCheckBox(int CaptionStrPart);
bool ValidatePublicKey(UnicodeString & Status);
};
//---------------------------------------------------------------------------
TSshHostCADialog::TSshHostCADialog(bool Add) :
TCustomDialog(HELP_SSH_HOST_CA)
{
ClientWidth = ScaleByTextHeight(this, 577);
Caption = LoadStr(Add ? SSH_HOST_CA_ADD : SSH_HOST_CA_EDIT);
NameEdit = new TEdit(this);
AddEdit(NameEdit, CreateLabel(LoadStr(SSH_HOST_CA_NAME)));
PublicKeyEdit = new TEdit(this);
AddEdit(PublicKeyEdit, CreateLabel(LoadStr(SSH_HOST_CA_PUBLIC_KEY)));
TButton * BrowseButton = CreateButton(this);
BrowseButton->Caption = LoadStr(SSH_HOST_CA_BROWSE);
BrowseButton->OnClick = BrowseButtonClick;
AddButtonNextToEdit(BrowseButton, PublicKeyEdit);
NameEdit->Width = PublicKeyEdit->Width;
PublicKeyLabel = new TEdit(this);
ReadOnlyControl(PublicKeyLabel);
PublicKeyLabel->BorderStyle = bsNone;
PublicKeyLabel->TabStop = false;
AddEditLikeControl(PublicKeyLabel, NULL);
ValidityExpressionEdit = new TEdit(this);
AddEdit(ValidityExpressionEdit, CreateLabel(LoadStr(SSH_HOST_CA_PUBLIC_HOSTS)));
TLabel * Label = CreateLabel(LoadStr(SSH_HOST_CA_SIGNATURE_TYPES));
AddText(Label);
PermitRsaSha1Check = AddValidityCheckBox(1);
int PermitCheckBoxTop = Label->Top - (PermitRsaSha1Check->Height - Label->Height) / 2;
PermitRsaSha1Check->Left = OKButton->Left + 1;
PermitRsaSha1Check->Top = PermitCheckBoxTop;
PermitRsaSha256Check = AddValidityCheckBox(2);
PermitRsaSha256Check->Left = CancelButton->Left + 1;
PermitRsaSha256Check->Top = PermitCheckBoxTop;
PermitRsaSha512Check = AddValidityCheckBox(3);
PermitRsaSha512Check->Left = HelpButton->Left + 1;
PermitRsaSha512Check->Top = PermitCheckBoxTop;
}
//---------------------------------------------------------------------------
TCheckBox * TSshHostCADialog::AddValidityCheckBox(int CaptionStrPart)
{
TCheckBox * Result = new TCheckBox(this);
Result->Parent = this;
Result->Caption = LoadStrPart(SSH_HOST_CA_SIGNATURES, CaptionStrPart);
ScaleButtonControl(Result);
Result->Left = Left;
Result->OnClick = Change;
AddWinControl(Result);
return Result;
}
//---------------------------------------------------------------------------
bool TSshHostCADialog::ValidatePublicKey(UnicodeString & Status)
{
bool Result = false;
UnicodeString PublicKeyText = PublicKeyEdit->Text.Trim();
if (PublicKeyText.IsEmpty())
{
Status = LoadStr(SSH_HOST_CA_NO_KEY);
}
else
{
RawByteString PublicKeyDummy;
try
{
ParseCertificatePublicKey(PublicKeyText, PublicKeyDummy, Status);
Result = true;
}
catch (Exception & E)
{
Status = E.Message;
}
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TSshHostCADialog::DoChange(bool & CanSubmit)
{
TCustomDialog::DoChange(CanSubmit);
UnicodeString PublicKeyStatus;
ValidatePublicKey(PublicKeyStatus);
// Should drop "SHA256:" prefix, the way we do in TSecureShell::VerifyHostKey
PublicKeyLabel->Text = PublicKeyStatus;
CanSubmit = !NameEdit->Text.Trim().IsEmpty() && !PublicKeyEdit->Text.Trim().IsEmpty();
}
//---------------------------------------------------------------------
void __fastcall TSshHostCADialog::DoValidate()
{
TCustomDialog::DoValidate();
UnicodeString PublicKeyStatus;
if (!ValidatePublicKey(PublicKeyStatus))
{
PublicKeyEdit->SetFocus();
throw Exception(MainInstructions(PublicKeyStatus));
}
if (ValidityExpressionEdit->Text.Trim().IsEmpty())
{
ValidityExpressionEdit->SetFocus();
throw Exception(MainInstructions(LoadStr(SSH_HOST_CA_NO_HOSTS)));
}
UnicodeString Error;
int ErrorStart, ErrorLen;
if (!IsCertificateValidityExpressionValid(ValidityExpressionEdit->Text, Error, ErrorStart, ErrorLen))
{
std::unique_ptr<TStrings> MoreMessages(TextToStringList(Error));
MoreMessageDialog(MainInstructions(LoadStr(SSH_HOST_CA_HOSTS_INVALID)), MoreMessages.get(), qtError, qaOK, HelpKeyword);
ValidityExpressionEdit->SetFocus();
ValidityExpressionEdit->SelStart = ErrorStart;
ValidityExpressionEdit->SelLength = ErrorLen;
Abort();
}
}
//---------------------------------------------------------------------------
bool TSshHostCADialog::Execute(TSshHostCA & SshHostCA)
{
NameEdit->Text = SshHostCA.Name;
RawByteString PublicKey = SshHostCA.PublicKey;
PublicKeyEdit->Text = EncodeStrToBase64(PublicKey);
ValidityExpressionEdit->Text = SshHostCA.ValidityExpression;
PermitRsaSha1Check->Checked = SshHostCA.PermitRsaSha1;
PermitRsaSha256Check->Checked = SshHostCA.PermitRsaSha256;
PermitRsaSha512Check->Checked = SshHostCA.PermitRsaSha512;
bool Result = TCustomDialog::Execute();
if (Result)
{
SshHostCA.Name = NameEdit->Text;
SshHostCA.PublicKey = DecodeBase64ToStr(PublicKeyEdit->Text);
SshHostCA.ValidityExpression = ValidityExpressionEdit->Text;
SshHostCA.PermitRsaSha1 = PermitRsaSha1Check->Checked;
SshHostCA.PermitRsaSha256 = PermitRsaSha256Check->Checked;
SshHostCA.PermitRsaSha512 = PermitRsaSha512Check->Checked;
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TSshHostCADialog::BrowseButtonClick(TObject *)
{
std::unique_ptr<TOpenDialog> OpenDialog(new TOpenDialog(Application));
OpenDialog->Title = LoadStr(SSH_HOST_CA_BROWSE_TITLE);
OpenDialog->Filter = LoadStr(SSH_HOST_CA_BROWSE_FILTER);
bool Result = OpenDialog->Execute();
if (Result)
{
UnicodeString FileName = OpenDialog->FileName;
UnicodeString Algorithm, Comment;
bool HasCertificate;
RawByteString PublicKey;
try
{
PublicKey = LoadPublicKey(FileName, Algorithm, Comment, HasCertificate);
}
catch (Exception & E)
{
throw ExtException(&E, MainInstructions(FMTLOAD(SSH_HOST_CA_LOAD_ERROR, (FileName))));
}
if (NameEdit->Text.IsEmpty())
{
NameEdit->Text = Comment;
}
PublicKeyEdit->Text = EncodeStrToBase64(PublicKey);
}
}
//---------------------------------------------------------------------------
bool DoSshHostCADialog(bool Add, TSshHostCA & SshHostCA)
{
std::unique_ptr<TSshHostCADialog> Dialog(new TSshHostCADialog(Add));
return Dialog->Execute(SshHostCA);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
class TTagDialog : public TCustomDialog
{
public:
TTagDialog(bool Add, TStrings * Tags);
bool Execute(UnicodeString & Key, UnicodeString & Value);
protected:
virtual void __fastcall DoChange(bool & CanSubmit);
virtual void __fastcall DoValidate();
private:
TEdit * KeyEdit;
TEdit * ValueEdit;
TStrings * FTags;
void ValidateTag(TEdit * Edit);
};
//---------------------------------------------------------------------------
TTagDialog::TTagDialog(bool Add, TStrings * Tags) :
TCustomDialog(HELP_TAG)
{
Caption = LoadStr(Add ? TAG_ADD : TAG_EDIT);
FTags = Tags;
KeyEdit = new TEdit(this);
KeyEdit->MaxLength = 128;
AddEdit(KeyEdit, CreateLabel(LoadStr(TAG_KEY)));
ValueEdit = new TEdit(this);
ValueEdit->MaxLength = 256;
AddEdit(ValueEdit, CreateLabel(LoadStr(TAG_VALUE)));
}
//---------------------------------------------------------------------------
bool TTagDialog::Execute(UnicodeString & Key, UnicodeString & Value)
{
// if we happen to get values longer than what we believed was possible, allow them.
KeyEdit->MaxLength = std::max(KeyEdit->MaxLength, Key.Length());
KeyEdit->Text = Key;
ValueEdit->MaxLength = std::max(ValueEdit->MaxLength, Value.Length());
ValueEdit->Text = Value;
bool Result = TCustomDialog::Execute();
if (Result)
{
Key = KeyEdit->Text;
Value = ValueEdit->Text;
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TTagDialog::DoChange(bool & CanSubmit)
{
CanSubmit = !KeyEdit->Text.IsEmpty();
}
//---------------------------------------------------------------------------
void TTagDialog::ValidateTag(TEdit * Edit)
{
// there are lot more in various scripts
UnicodeString InvalidChars = L"!\"#$%&'()*,;<>?[\\]^`{|}~¡¢£¤¥¦§¨©«¬­®¯°±´¶·¸»¿×÷";
UnicodeString Text = Edit->Text;
for (int Index = 1; Index <= Text.Length(); Index++)
{
wchar_t Ch = Text[Index];
if (TCharacter::IsControl(Ch) ||
(InvalidChars.Pos(Ch) > 0))
{
UnicodeString Message = MainInstructions(FMTLOAD(TAG_INVALID_CHAR, (Ch)));
if (MoreMessageDialog(Message, NULL, qtWarning, qaIgnore | qaAbort, HelpKeyword) != qaIgnore)
{
Edit->SetFocus();
Abort();
}
else
{
break;
}
}
}
}
//---------------------------------------------------------------------------
void __fastcall TTagDialog::DoValidate()
{
UnicodeString Key = KeyEdit->Text;
if (FTags->IndexOf(Key) >= 0)
{
throw Exception(MainInstructions(LoadStr(TAG_NOT_UNIQUE)));
}
ValidateTag(KeyEdit);
ValidateTag(ValueEdit);
TCustomDialog::DoValidate();
}
//---------------------------------------------------------------------------
bool DoTagDialog(bool Add, TStrings * Tags, UnicodeString & Key, UnicodeString & Value)
{
std::unique_ptr<TTagDialog> Dialog(new TTagDialog(Add, Tags));
return Dialog->Execute(Key, Value);
}