1
0
mirror of https://github.com/winscp/winscp.git synced 2026-10-24 02:28:55 +03:00
Files
winscp/source/forms/Rights.cpp
2019-01-06 01:46:57 +01:00

712 lines
20 KiB
C++

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include <Common.h>
#include "Rights.h"
#include <VCLCommon.h>
#include <Tools.h>
#include <GUITools.h>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "GrayedCheckBox"
#pragma link "PngImageList"
#ifndef NO_RESOURCES
#pragma resource "*.dfm"
#endif
//---------------------------------------------------------------------------
__fastcall TRightsFrame::TRightsFrame(TComponent* Owner)
: TFrame(Owner)
{
FAddXToDirectoriesSuffix = L"+x";
FOnChange = NULL;
FAllowAddXToDirectories = true;
FPopup = false;
FPopupParent = NULL;
FDefaultButton = NULL;
FCancelButton = NULL;
// to avoid duplication of reference in forms that uses the frame
PopupMenu = RightsPopup;
FPopingContextMenu = false;
FInitialized = false;
#define COPY_HINT(R) \
Checks[TRights::rrGroup ## R]->Hint = Checks[TRights::rrUser ## R]->Hint; \
Checks[TRights::rrOther ## R]->Hint = Checks[TRights::rrUser ## R]->Hint;
COPY_HINT(Read);
COPY_HINT(Write);
COPY_HINT(Exec);
#undef COPY_HINT
UpgradeSpeedButton(OwnerButton);
UpgradeSpeedButton(GroupButton);
UpgradeSpeedButton(OthersButton);
}
//---------------------------------------------------------------------------
__fastcall TRightsFrame::~TRightsFrame()
{
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::SetStates(TRights::TRight Right, TRights::TState value)
{
DebugAssert(((value == TRights::rsNo) || (value == TRights::rsYes) || (value == TRights::rsUndef)));
TCheckBox * CheckBox = Checks[Right];
if (CheckBox != NULL)
{
switch (value) {
case TRights::rsNo: CheckBox->State = cbUnchecked; break;
case TRights::rsYes: CheckBox->State = cbChecked; break;
case TRights::rsUndef: CheckBox->State = cbGrayed; break;
}
}
}
//---------------------------------------------------------------------------
TRights::TState __fastcall TRightsFrame::GetStates(TRights::TRight Right)
{
TCheckBox * CheckBox = Checks[Right];
if (CheckBox != NULL)
{
switch (CheckBox->State) {
case cbUnchecked: return TRights::rsNo;
case cbChecked: return TRights::rsYes;
case cbGrayed:
default: return TRights::rsUndef;
}
}
else
{
return TRights::rsNo;
}
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::SetRights(const TRights & value)
{
bool Changed = (AllowUndef != value.AllowUndef);
AllowUndef = true; // temporarily
for (int Right = TRights::rrFirst; Right <= TRights::rrLast; Right++)
{
TRights::TRight R = static_cast<TRights::TRight>(Right);
if (States[R] != value.RightUndef[R])
{
States[R] = value.RightUndef[R];
Changed = true;
}
}
AllowUndef = value.AllowUndef;
if (Changed || !FInitialized)
{
UpdateControls();
}
}
//---------------------------------------------------------------------------
TRights __fastcall TRightsFrame::GetRights()
{
TRights Result;
Result.AllowUndef = AllowUndef;
for (int Right = TRights::rrFirst; Right <= TRights::rrLast; Right++)
{
Result.RightUndef[static_cast<TRights::TRight>(Right)] =
States[static_cast<TRights::TRight>(Right)];
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::SetAllowUndef(bool value)
{
for (int Right = TRights::rrFirst; Right <= TRights::rrLast; Right++)
{
TCheckBox * CheckBox = Checks[static_cast<TRights::TRight>(Right)];
if (CheckBox != NULL)
{
CheckBox->AllowGrayed = value;
}
}
}
//---------------------------------------------------------------------------
bool __fastcall TRightsFrame::GetAllowUndef()
{
bool Result = false, First = true;
for (int Right = TRights::rrFirst; Right <= TRights::rrLast; Right++)
{
TCheckBox * Check = Checks[static_cast<TRights::TRight>(Right)];
if (Check != NULL)
{
if (First)
{
Result = Check->AllowGrayed;
First = false;
}
else if (Result != Check->AllowGrayed)
{
DebugFail();
}
}
}
return Result;
}
//---------------------------------------------------------------------------
TCheckBox * __fastcall TRightsFrame::GetChecks(TRights::TRight Right)
{
for (int Index = 0; Index < ControlCount; Index++)
{
if (Controls[Index]->InheritsFrom(__classid(TCheckBox)) &&
(Controls[Index]->Tag == TRights::RightToFlag(Right)))
{
return ((TCheckBox *)Controls[Index]);
}
}
return NULL;
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::SetAddXToDirectories(bool value)
{
DirectoriesXCheck->Checked = value;
}
//---------------------------------------------------------------------------
bool __fastcall TRightsFrame::GetAddXToDirectories()
{
return DirectoriesXCheck->Checked;
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::ControlChange(TObject * /*Sender*/)
{
UpdateControls();
}
//---------------------------------------------------------------------------
bool __fastcall TRightsFrame::DirectoriesXEffective()
{
return !((Rights.NumberSet & TRights::rfExec) == TRights::rfExec);
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::UpdateControls()
{
if (!OctalEdit->Focused())
{
UpdateOctalEdit();
}
Color = (FPopup ? clWindow : clBtnFace);
DirectoriesXCheck->Visible = AllowAddXToDirectories;
EnableControl(DirectoriesXCheck,
Enabled && DirectoriesXEffective());
FInitialized = true;
DoChange();
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::CycleRights(int Group)
{
TRights::TState State;
bool Same = true;
for (int Right = 0; Right < 3; Right++)
{
TRights::TState CState = States[static_cast<TRights::TRight>(
TRights::rrUserRead + Right + ((Group - 1) * 3))];
if (Right == 0) State = CState;
else
if (State != CState) Same = False;
}
if (!Same)
{
State = TRights::rsYes;
}
else
{
switch (State) {
case TRights::rsYes:
State = TRights::rsNo;
break;
case TRights::rsNo:
State = AllowUndef ? TRights::rsUndef : TRights::rsYes;
break;
case TRights::rsUndef:
State = TRights::rsYes;
break;
}
}
for (int Right = 0; Right < 3; Right++)
{
States[static_cast<TRights::TRight>(
TRights::rrUserRead + Right + ((Group - 1) * 3))] = State;
}
UpdateControls();
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::RightsButtonsClick(TObject *Sender)
{
CycleRights(((TComponent*)Sender)->Tag);
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::SetAllowAddXToDirectories(bool value)
{
if ((FAllowAddXToDirectories != value) || !FInitialized)
{
FAllowAddXToDirectories = value;
UpdateControls();
}
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::DoChange()
{
if (FOnChange)
{
FOnChange(this);
}
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::SetEnabled(bool Value)
{
TFrame::SetEnabled(Value);
UpdateControls();
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::ForceUpdate()
{
UpdateOctalEdit();
}
//---------------------------------------------------------------------------
bool __fastcall TRightsFrame::HasFocus()
{
return
(Focused() ||
((Screen->ActiveControl != NULL) && (Screen->ActiveControl->Parent == this))) ||
((PopupParent != NULL) && PopupParent->Focused());
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::RightsActionsExecute(TBasicAction * Action,
bool & Handled)
{
// prevent shortcuts to be evaluated when frame does not have a focus
if (HasFocus())
{
bool Changed = true;
TRights R = Rights;
R.Number = TRights::rfNo;
Handled = true;
if (Action == NoRightsAction)
{
R = TRights::rfNo;
}
else if (Action == DefaultRightsAction)
{
R = TRights::rfDefault;
}
else if (Action == AllRightsAction)
{
R = TRights::rfAll;
}
else if (Action == LeaveRightsAsIsAction)
{
R.AllUndef();
}
else if (Action == CopyTextAction)
{
TInstantOperationVisualizer Visualizer;
CopyToClipboard(Text);
Changed = false;
}
else if (Action == CopyOctalAction)
{
TRights R = Rights;
DebugAssert(!R.IsUndef);
if (!R.IsUndef)
{
TInstantOperationVisualizer Visualizer;
CopyToClipboard(R.Octal);
}
Changed = false;
}
else if (Action == PasteAction)
{
UnicodeString S;
if (TextFromClipboard(S, true))
{
Text = S;
}
// trigger on change event, even if no change actually occurred to
// allow parent form to visualize feedback of an action
DoChange();
// Update octal edit in Rights frame even if it has focus
ForceUpdate();
Changed = false;
}
else
{
Handled = false;
}
if (Changed)
{
Rights = R;
ForceUpdate();
DoChange();
}
}
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::RightsActionsUpdate(TBasicAction *Action,
bool &Handled)
{
TRights R = Rights;
Handled = true;
if (Action == NoRightsAction)
{
// explicitly enable as action gets disabled, if its shortcut is pressed,
// while the form does not have a focus and OnExecute handler denies the execution
NoRightsAction->Enabled = true;
NoRightsAction->Checked = !R.IsUndef && (R.NumberSet == TRights::rfNo);
}
else if (Action == DefaultRightsAction)
{
DefaultRightsAction->Enabled = true;
DefaultRightsAction->Checked = !R.IsUndef && (R.NumberSet == TRights::rfDefault);
}
else if (Action == AllRightsAction)
{
AllRightsAction->Enabled = true;
AllRightsAction->Checked = !R.IsUndef && (R.NumberSet == TRights::rfAll);
}
else if (Action == LeaveRightsAsIsAction)
{
LeaveRightsAsIsAction->Enabled = true;
LeaveRightsAsIsAction->Visible = R.AllowUndef;
LeaveRightsAsIsAction->Checked = (R.NumberSet == TRights::rfNo) &&
(R.NumberUnset == TRights::rfNo);
}
else if (Action == CopyTextAction)
{
CopyTextAction->Enabled = !R.IsUndef;
}
else if (Action == CopyOctalAction)
{
CopyOctalAction->Enabled = !R.IsUndef;
}
else if (Action == PasteAction)
{
PasteAction->Enabled = IsFormatInClipboard(CF_TEXT);
}
else
{
Handled = false;
}
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::CreateParams(TCreateParams & Params)
{
TFrame::CreateParams(Params);
if (FPopup)
{
Params.Style |= WS_BORDER;
}
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::CreateWnd()
{
if (FPopup)
{
Width += 2 * GetSystemMetricsForControl(Parent, SM_CXBORDER);
Height += 2 * GetSystemMetricsForControl(Parent, SM_CYBORDER);
}
TFrame::CreateWnd();
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::SetPopup(bool value)
{
if (Popup != value)
{
FPopup = value;
Visible = !FPopup;
CloseButton->Visible = value;
CloseButton->Cancel = value;
CloseButton->Default = value;
}
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::DoCloseUp()
{
Hide();
if (FDefaultButton != NULL)
{
FDefaultButton->Default = true;
FDefaultButton = NULL;
}
if (FCancelButton != NULL)
{
FCancelButton->Cancel = true;
FCancelButton = NULL;
}
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::DoExit()
{
// this is bit hack to make frame hide when ComboEdit button is pressed while
// from is poped-up already.
if (FPopup && !IsAncestor(Screen->ActiveControl, FPopupParent))
{
DoCloseUp();
}
TFrame::DoExit();
}
//---------------------------------------------------------------------------
bool __fastcall TRightsFrame::IsAncestor(TControl * Control, TControl * Ancestor)
{
while ((Control != NULL) &&
(Control->Parent != Ancestor))
{
Control = Control->Parent;
}
return (Control != NULL);
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::WMContextMenu(TWMContextMenu & Message)
{
FPopingContextMenu = true;
try
{
TFrame::Dispatch(&Message);
}
__finally
{
FPopingContextMenu = false;
}
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::CMDialogKey(TCMDialogKey & Message)
{
if (FPopup && Visible &&
((Message.CharCode == VK_RETURN) ||
(Message.CharCode == VK_ESCAPE)) &&
KeyDataToShiftState(Message.KeyData).Empty())
{
CloseUp();
Message.Result = 1;
}
else
{
TFrame::Dispatch(&Message);
}
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::CMCancelMode(TCMCancelMode & Message)
{
if (FPopup && Visible && !FPopingContextMenu &&
((Message.Sender == NULL) ||
(!IsAncestor(Message.Sender, this) &&
!IsAncestor(Message.Sender, FPopupParent) &&
(Message.Sender != this))))
{
CloseUp();
}
TFrame::Dispatch(&Message);
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::Dispatch(void * Message)
{
TMessage & AMessage = *static_cast<TMessage *>(Message);
switch (AMessage.Msg)
{
case CM_CANCELMODE:
CMCancelMode(*(TCMCancelMode *)Message);
break;
case CM_DIALOGKEY:
CMDialogKey(*(TCMDialogKey *)Message);
break;
case WM_CONTEXTMENU:
WMContextMenu(*(TWMContextMenu *)Message);
break;
default:
TFrame::Dispatch(Message);
break;
}
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::DropDown()
{
TCustomForm * Form = GetParentForm(this);
// due to lack of better idea, we clear "default" and "cancel" flags of respective
// form buttons to prevent them to handle ESC/ENTER keys.
for (int Index = 0; Index < Form->ControlCount; Index++)
{
TButton * Button = dynamic_cast<TButton *>(Form->Controls[Index]);
if (Button != NULL)
{
if (Button->Default)
{
DebugAssert(FDefaultButton == NULL);
FDefaultButton = Button;
Button->Default = false;
}
if (Button->Cancel)
{
DebugAssert(FCancelButton == NULL);
FCancelButton = Button;
Button->Cancel = false;
}
}
}
TPoint Origin(PopupParent->Left, PopupParent->Top + PopupParent->Height);
Origin = Parent->ScreenToClient(PopupParent->Parent->ClientToScreen(Origin));
if (Origin.x + Width > Parent->ClientWidth)
{
Origin.x += PopupParent->Width - Width;
}
Left = Origin.x;
Top = Origin.y;
Show();
SetFocus();
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::CloseUp()
{
DebugAssert(FPopup);
DebugAssert(Visible);
if (!Focused())
{
// this can happen only if called from on-click handler of drop down button
DoCloseUp();
}
FPopupParent->SetFocus();
}
//---------------------------------------------------------------------------
UnicodeString __fastcall TRightsFrame::GetText()
{
UnicodeString Result = Rights.Text;
if (AllowAddXToDirectories && DirectoriesXEffective() && AddXToDirectories)
{
Result = FORMAT(L"%s (%s)", (Result, FAddXToDirectoriesSuffix));
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::SetText(UnicodeString value)
{
if (Text != value)
{
UnicodeString RightsStr = value;
int P = RightsStr.LowerCase().Pos(FAddXToDirectoriesSuffix);
bool AAddXToDirectories = (P > 0);
if (AAddXToDirectories)
{
RightsStr.Delete(P, FAddXToDirectoriesSuffix.Length());
}
RightsStr = DeleteChar(DeleteChar(RightsStr, L'('), L')').Trim();
TRights R = Rights;
if (((RightsStr.Length() == 3) || (RightsStr.Length() == 4)) &&
IsNumber(RightsStr))
{
R.Octal = RightsStr;
}
else
{
R.Text = RightsStr;
}
Rights = R;
AddXToDirectories = AAddXToDirectories;
}
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::RightsPopupPopup(TObject * /*Sender*/)
{
if (!HasFocus())
{
SetFocus();
}
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::FrameContextPopup(TObject * Sender,
TPoint & MousePos, bool & Handled)
{
SelectScaledImageList(RightsImages);
MenuPopup(Sender, MousePos, Handled);
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::UpdateByOctal()
{
if (!OctalEdit->Text.IsEmpty())
{
TRights R = Rights;
R.Octal = OctalEdit->Text;
Rights = R;
}
UpdateControls();
OctalEdit->Modified = false;
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::UpdateOctalEdit()
{
TRights R = Rights;
OctalEdit->Text = R.IsUndef ? UnicodeString() : R.Octal;
OctalEdit->Modified = false;
OctalEdit->SelectAll();
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::OctalEditChange(TObject *)
{
if (OctalEdit->Modified && OctalEdit->Text.Length() >= 3)
{
try
{
UpdateByOctal();
}
catch(...)
{
OctalEdit->Modified = true;
}
}
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::OctalEditExit(TObject *)
{
if (!Visible)
{
// should happen only if popup is closed by esc key
DebugAssert(Popup);
// cancel changes
ForceUpdate();
}
else if (OctalEdit->Modified)
{
// Now the text in OctalEdit is almost necessarily invalid, otherwise
// OctalEditChange would have already cleared Modified flag
try
{
UpdateByOctal();
}
catch(...)
{
OctalEdit->SelectAll();
OctalEdit->SetFocus();
throw;
}
}
else
{
UpdateControls();
}
}
//---------------------------------------------------------------------------
void __fastcall TRightsFrame::CloseButtonClick(TObject *)
{
CloseUp();
}
//---------------------------------------------------------------------------