mirror of
https://github.com/winscp/winscp.git
synced 2026-10-24 02:28:55 +03:00
Bug 2125: Displaying current version on the New version notification + Contents of About dialog can be copied to the clipboard using Ctrl+C
https://winscp.net/tracker/2125 Source commit: 50ae66db19efb1f756ea809faad22a8067d53bff
This commit is contained in:
@@ -3224,6 +3224,116 @@ UnicodeString __fastcall FormatDateTimeSpan(const UnicodeString TimeFormat, TDat
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString FormatRelativeTime(const TDateTime & ANow, const TDateTime & AThen, bool DateOnly)
|
||||
{
|
||||
UnicodeString Result;
|
||||
if (DateOnly)
|
||||
{
|
||||
if (IsSameDay(AThen, ANow - 1))
|
||||
{
|
||||
Result = LoadStrPart(TIME_RELATIVE, 3);
|
||||
}
|
||||
else if (IsSameDay(AThen, ANow))
|
||||
{
|
||||
Result = LoadStrPart(TIME_RELATIVE, 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (Result.IsEmpty())
|
||||
{
|
||||
int Part, Num;
|
||||
|
||||
Num = YearsBetween(ANow, AThen);
|
||||
if (Num > 1)
|
||||
{
|
||||
Part = 18;
|
||||
}
|
||||
else if (Num == 1)
|
||||
{
|
||||
Part = 17;
|
||||
}
|
||||
else
|
||||
{
|
||||
Num = MonthsBetween(ANow, AThen);
|
||||
if (Num > 1)
|
||||
{
|
||||
Part = 16;
|
||||
}
|
||||
else if (Num == 1)
|
||||
{
|
||||
Part = 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
Num = DaysBetween(ANow, AThen);
|
||||
if (Num > 1)
|
||||
{
|
||||
Part = 12;
|
||||
}
|
||||
else if (Num == 1)
|
||||
{
|
||||
Part = 11;
|
||||
}
|
||||
else
|
||||
{
|
||||
Num = static_cast<int>(HoursBetween(ANow, AThen));
|
||||
if (Num > 1)
|
||||
{
|
||||
Part = 10;
|
||||
}
|
||||
else if (Num == 1)
|
||||
{
|
||||
Part = 9;
|
||||
}
|
||||
else
|
||||
{
|
||||
Num = static_cast<int>(MinutesBetween(ANow, AThen));
|
||||
if (Num > 1)
|
||||
{
|
||||
Part = 8;
|
||||
}
|
||||
else if (Num == 1)
|
||||
{
|
||||
Part = 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
Num = static_cast<int>(SecondsBetween(ANow, AThen));
|
||||
if (Num > 1)
|
||||
{
|
||||
Part = 6;
|
||||
}
|
||||
else if (Num == 1)
|
||||
{
|
||||
Part = 5;
|
||||
}
|
||||
else if (Num == 0)
|
||||
{
|
||||
Part = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugFail();
|
||||
Part = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DebugAlwaysTrue(Part >= 0))
|
||||
{
|
||||
Result = FORMAT(LoadStrPart(TIME_RELATIVE, Part), (abs(Num)));
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = FormatDateTime(L"ddddd", AThen);
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString __fastcall ExtractFileBaseName(const UnicodeString & Path)
|
||||
{
|
||||
return ChangeFileExt(ExtractFileName(Path), L"");
|
||||
@@ -4347,3 +4457,8 @@ void NotImplemented()
|
||||
DebugFail();
|
||||
throw Exception(L"Not implemented");
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString GetDividerLine()
|
||||
{
|
||||
return UnicodeString::StringOfChar(L'-', 27);
|
||||
}
|
||||
|
||||
@@ -194,6 +194,7 @@ void SetStringValueEvenIfEmpty(TStrings * Strings, const UnicodeString & Name, c
|
||||
UnicodeString __fastcall GetAncestorProcessName(int Levels = 1);
|
||||
UnicodeString GetAncestorProcessNames();
|
||||
void NotImplemented();
|
||||
UnicodeString GetDividerLine();
|
||||
//---------------------------------------------------------------------------
|
||||
struct TSearchRecSmart : public TSearchRec
|
||||
{
|
||||
@@ -267,6 +268,7 @@ int __fastcall TimeToMSec(TDateTime T);
|
||||
int __fastcall TimeToSeconds(TDateTime T);
|
||||
int __fastcall TimeToMinutes(TDateTime T);
|
||||
UnicodeString __fastcall FormatDateTimeSpan(const UnicodeString TimeFormat, TDateTime DateTime);
|
||||
UnicodeString FormatRelativeTime(const TDateTime & ANow, const TDateTime & AThen, bool DateOnly);
|
||||
TStrings * TlsCipherList();
|
||||
//---------------------------------------------------------------------------
|
||||
template<class MethodT>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <shlobj.h>
|
||||
#include <System.IOUtils.hpp>
|
||||
#include <System.StrUtils.hpp>
|
||||
#include <System.DateUtils.hpp>
|
||||
//---------------------------------------------------------------------------
|
||||
#pragma package(smart_init)
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -1000,38 +1001,40 @@ bool __fastcall TConfiguration::GetIsUnofficial()
|
||||
#endif
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString __fastcall TConfiguration::GetVersionStr()
|
||||
UnicodeString TConfiguration::FormatVersionStr(bool Verbose)
|
||||
{
|
||||
TGuard Guard(FCriticalSection);
|
||||
try
|
||||
{
|
||||
UnicodeString BuildStr;
|
||||
if (!IsUnofficial)
|
||||
if (!IsUnofficial || Verbose)
|
||||
{
|
||||
BuildStr = LoadStr(VERSION_BUILD);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
BuildStr = LoadStr(VERSION_DEBUG_BUILD);
|
||||
#else
|
||||
BuildStr = LoadStr(VERSION_DEV_BUILD);
|
||||
#endif
|
||||
if (!IsUnofficial)
|
||||
{
|
||||
BuildStr = LoadStr(VERSION_BUILD);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
BuildStr = LoadStr(VERSION_DEBUG_BUILD);
|
||||
#else
|
||||
BuildStr = LoadStr(VERSION_DEV_BUILD);
|
||||
#endif
|
||||
}
|
||||
|
||||
int Build = LOWORD(FixedApplicationInfo->dwFileVersionLS);
|
||||
if (Build > 0)
|
||||
{
|
||||
BuildStr += L" " + IntToStr(Build);
|
||||
}
|
||||
}
|
||||
|
||||
int Build = LOWORD(FixedApplicationInfo->dwFileVersionLS);
|
||||
if (Build > 0)
|
||||
{
|
||||
BuildStr += L" " + IntToStr(Build);
|
||||
}
|
||||
|
||||
UnicodeString BuildDate = __DATE__;
|
||||
UnicodeString MonthStr = CutToChar(BuildDate, L' ', true);
|
||||
UnicodeString BuildDateStr = __DATE__;
|
||||
UnicodeString MonthStr = CutToChar(BuildDateStr, L' ', true);
|
||||
int Month = ParseShortEngMonthName(MonthStr);
|
||||
int Day = StrToInt(CutToChar(BuildDate, L' ', true));
|
||||
int Year = StrToInt(Trim(BuildDate));
|
||||
UnicodeString DateStr = FORMAT(L"%d-%2.2d-%2.2d", (Year, Month, Day));
|
||||
AddToList(BuildStr, DateStr, L" ");
|
||||
int Day = StrToInt(CutToChar(BuildDateStr, L' ', true));
|
||||
int Year = StrToInt(Trim(BuildDateStr));
|
||||
TDateTime BuildDate = EncodeDateVerbose(static_cast<Word>(Year), static_cast<Word>(Month), static_cast<Word>(Day));
|
||||
|
||||
UnicodeString FullVersion = Version;
|
||||
|
||||
@@ -1043,11 +1046,34 @@ UnicodeString __fastcall TConfiguration::GetVersionStr()
|
||||
FullVersion += L" " + AReleaseType;
|
||||
}
|
||||
|
||||
UnicodeString Result = FMTLOAD(VERSION2, (FullVersion, BuildStr));
|
||||
UnicodeString Fmt;
|
||||
UnicodeString DateStr;
|
||||
if (Verbose)
|
||||
{
|
||||
DateStr = FormatDateTime(L"yyyy-mm-dd", BuildDate);
|
||||
Fmt = LoadStr(VERSION2);
|
||||
}
|
||||
else
|
||||
{
|
||||
TDateTime ANow = Now();
|
||||
if (BuildDate < ANow)
|
||||
{
|
||||
DateStr = FormatRelativeTime(ANow, BuildDate, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
DateStr = FormatDateTime(L"ddddd", BuildDate);
|
||||
}
|
||||
|
||||
#ifndef BUILD_OFFICIAL
|
||||
Result += L" " + LoadStr(VERSION_DONT_DISTRIBUTE);
|
||||
#endif
|
||||
Fmt = L"%s (%s)";
|
||||
}
|
||||
AddToList(BuildStr, DateStr, L" ");
|
||||
UnicodeString Result = FORMAT(Fmt, (FullVersion, BuildStr));
|
||||
|
||||
if (!IsUnofficial && Verbose)
|
||||
{
|
||||
Result += L" " + LoadStr(VERSION_DONT_DISTRIBUTE);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
@@ -1057,6 +1083,11 @@ UnicodeString __fastcall TConfiguration::GetVersionStr()
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString __fastcall TConfiguration::GetVersionStr()
|
||||
{
|
||||
return FormatVersionStr(true);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString __fastcall TConfiguration::GetFileVersion(const UnicodeString & FileName)
|
||||
{
|
||||
UnicodeString Result;
|
||||
|
||||
@@ -270,6 +270,7 @@ public:
|
||||
bool RegistryPathExists(const UnicodeString & RegistryPath);
|
||||
bool HasLocalPortNumberLimits();
|
||||
virtual UnicodeString TemporaryDir(bool Mask = false) = 0;
|
||||
UnicodeString FormatVersionStr(bool IncludeOfficialBuildNumber);
|
||||
|
||||
TStoredSessionList * __fastcall SelectFilezillaSessionsForImport(
|
||||
TStoredSessionList * Sessions, UnicodeString & Error);
|
||||
|
||||
@@ -397,3 +397,43 @@ void __fastcall TAboutDialog::Dispatch(void * Message)
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TAboutDialog::FormKeyDown(TObject *, WORD & Key, TShiftState Shift)
|
||||
{
|
||||
if ((Key == L'C') && Shift.Contains(ssCtrl))
|
||||
{
|
||||
if ((FThirdPartyWebBrowser != NULL) &&
|
||||
FThirdPartyWebBrowser->Focused() &&
|
||||
(FThirdPartyWebBrowser->SelLength() > 0))
|
||||
{
|
||||
// Let the browser handle the Ctrl+C
|
||||
}
|
||||
else
|
||||
{
|
||||
UnicodeString Text =
|
||||
ApplicationLabel->Caption + sLineBreak +
|
||||
VersionLabel->Caption + sLineBreak +
|
||||
sLineBreak +
|
||||
WinSCPCopyrightLabel->Caption + sLineBreak +
|
||||
HomepageLabel->Caption + sLineBreak +
|
||||
sLineBreak +
|
||||
ProductSpecificMessageLabel->Caption + sLineBreak +
|
||||
ForumUrlLabel->Caption + sLineBreak;
|
||||
|
||||
UnicodeString ThirdPartyText;
|
||||
if ((FThirdPartyWebBrowser != NULL) &&
|
||||
CopyTextFromBrowser(FThirdPartyWebBrowser, ThirdPartyText))
|
||||
{
|
||||
Text +=
|
||||
sLineBreak +
|
||||
GetDividerLine() + sLineBreak +
|
||||
Label3->Caption + sLineBreak +
|
||||
ThirdPartyText + sLineBreak;
|
||||
}
|
||||
|
||||
TInstantOperationVisualizer Visualizer;
|
||||
CopyToClipboard(Text);
|
||||
Key = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -10,8 +10,10 @@ object AboutDialog: TAboutDialog
|
||||
ClientWidth = 410
|
||||
Color = clBtnFace
|
||||
ParentFont = True
|
||||
KeyPreview = True
|
||||
OldCreateOrder = True
|
||||
Position = poOwnerFormCenter
|
||||
OnKeyDown = FormKeyDown
|
||||
DesignSize = (
|
||||
410
|
||||
501)
|
||||
|
||||
@@ -39,6 +39,7 @@ __published:
|
||||
void __fastcall OKButtonMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
|
||||
int X, int Y);
|
||||
void __fastcall IconPaintBoxPaint(TObject *Sender);
|
||||
void __fastcall FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift);
|
||||
private:
|
||||
TConfiguration * FConfiguration;
|
||||
TNotifyEvent FOnRegistrationLink;
|
||||
|
||||
@@ -209,7 +209,7 @@ UnicodeString __fastcall TMessageForm::GetFormText()
|
||||
{
|
||||
UnicodeString DividerLine, ButtonCaptions;
|
||||
|
||||
DividerLine = UnicodeString::StringOfChar(L'-', 27) + sLineBreak;
|
||||
DividerLine = GetDividerLine() + sLineBreak;
|
||||
for (int i = 0; i < ComponentCount - 1; i++)
|
||||
{
|
||||
if (dynamic_cast<TButton*>(Components[i]) != NULL)
|
||||
@@ -224,19 +224,13 @@ UnicodeString __fastcall TMessageForm::GetFormText()
|
||||
{
|
||||
MoreMessages = MessageMemo->Text + DividerLine;
|
||||
}
|
||||
else if (MessageBrowser != NULL)
|
||||
else if ((MessageBrowser != NULL) && CopyTextFromBrowser(MessageBrowser, MoreMessages))
|
||||
{
|
||||
MessageBrowser->SelectAll();
|
||||
MessageBrowser->CopyToClipBoard();
|
||||
if (NonEmptyTextFromClipboard(MoreMessages))
|
||||
if (!EndsStr(sLineBreak, MoreMessages))
|
||||
{
|
||||
if (!EndsStr(sLineBreak, MoreMessages))
|
||||
{
|
||||
MoreMessages += sLineBreak;
|
||||
}
|
||||
MoreMessages += DividerLine;
|
||||
MoreMessages += sLineBreak;
|
||||
}
|
||||
MessageBrowser->DoCommand(L"UNSELECT");
|
||||
MoreMessages += DividerLine;
|
||||
}
|
||||
UnicodeString MessageCaption = NormalizeNewLines(MessageText);
|
||||
UnicodeString Result = FORMAT(L"%s%s%s%s%s%s%s%s%s%s%s", (DividerLine, Caption, sLineBreak,
|
||||
|
||||
@@ -496,6 +496,7 @@
|
||||
#define COPY_INFO_EXCLUDE_EMPTY_DIRS 566
|
||||
#define PUBLIC_KEY_UPLOADED 567
|
||||
#define PUBLIC_KEY_PERMISSIONS 568
|
||||
#define TIME_RELATIVE 569
|
||||
|
||||
#define CORE_VARIABLE_STRINGS 600
|
||||
#define PUTTY_BASED_ON 601
|
||||
|
||||
@@ -465,6 +465,7 @@ BEGIN
|
||||
COPY_INFO_EXCLUDE_EMPTY_DIRS, "Exclude empty directories"
|
||||
PUBLIC_KEY_UPLOADED, "**Public key \"%s\" was installed.**\n\nYou can now login to the server using the key pair."
|
||||
PUBLIC_KEY_PERMISSIONS, "Though potentially wrong permissions of \"%s\" file and/or its parent folder were detected. Please check them."
|
||||
TIME_RELATIVE, "just now|today|yesterday|tomorrow|one second ago|%d seconds ago|one minute ago|%d minutes ago|one hour ago|%d hours ago|one day ago|%d days ago|one week ago|%d weeks ago|one month ago|%d months ago|one year ago|%d years ago"
|
||||
|
||||
CORE_VARIABLE_STRINGS, "CORE_VARIABLE"
|
||||
PUTTY_BASED_ON, "SSH and SCP code based on PuTTY %s"
|
||||
|
||||
@@ -309,6 +309,7 @@
|
||||
#define STORE_MIGRATION_LEARN 1596
|
||||
#define MESSAGE_DISMISS 1597
|
||||
#define USAGE_PASSWORDSFROMFILES 1598
|
||||
#define UPDATE_CURRENT 1599
|
||||
|
||||
#define WIN_FORMS_STRINGS 1600
|
||||
#define COPY_FILE 1605
|
||||
|
||||
@@ -314,6 +314,7 @@ BEGIN
|
||||
STORE_MIGRATION_LEARN, "Learn about transitioning from classic installation."
|
||||
MESSAGE_DISMISS, "Dismiss"
|
||||
USAGE_PASSWORDSFROMFILES, "Read all passwords from files"
|
||||
UPDATE_CURRENT, "Your version: %s"
|
||||
|
||||
WIN_FORMS_STRINGS, "WIN_FORMS_STRINGS"
|
||||
COPY_FILE, "%s file '%s' to %s:"
|
||||
|
||||
@@ -1444,6 +1444,15 @@ void HideBrowserScrollbars(TWebBrowserEx * WebBrowser)
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool CopyTextFromBrowser(TWebBrowserEx * WebBrowser, UnicodeString & Text)
|
||||
{
|
||||
WebBrowser->SelectAll();
|
||||
WebBrowser->CopyToClipBoard();
|
||||
bool Result = NonEmptyTextFromClipboard(Text);
|
||||
WebBrowser->DoCommand(L"UNSELECT");
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString GenerateAppHtmlPage(TFont * Font, TPanel * Parent, const UnicodeString & Body, bool Seamless)
|
||||
{
|
||||
UnicodeString Result =
|
||||
|
||||
@@ -58,6 +58,7 @@ void __fastcall NavigateBrowserToUrl(TWebBrowserEx * WebBrowser, const UnicodeSt
|
||||
void ReadyBrowserForStreaming(TWebBrowserEx * WebBrowser);
|
||||
void WaitBrowserToIdle(TWebBrowserEx * WebBrowser);
|
||||
void HideBrowserScrollbars(TWebBrowserEx * WebBrowser);
|
||||
bool CopyTextFromBrowser(TWebBrowserEx * WebBrowser, UnicodeString & Text);
|
||||
UnicodeString GenerateAppHtmlPage(TFont * Font, TPanel * Parent, const UnicodeString & Body, bool Seamless);
|
||||
void LoadBrowserDocument(TWebBrowserEx * WebBrowser, const UnicodeString & Document);
|
||||
TComponent * __fastcall FindComponentRecursively(TComponent * Root, const UnicodeString & Name);
|
||||
|
||||
@@ -1659,6 +1659,11 @@ bool __fastcall CheckForUpdates(bool CachedResults)
|
||||
Message += L"\n\n" +
|
||||
FMTLOAD(UPDATE_NEXT, (FormatDateTime("ddddd", Updates.LastCheck + Updates.Period)));
|
||||
}
|
||||
else if (New)
|
||||
{
|
||||
UnicodeString Version = Configuration->FormatVersionStr(false);
|
||||
Message += L"\n\n" + FMTLOAD(UPDATE_CURRENT, (Version));
|
||||
}
|
||||
|
||||
int Answers = qaOK |
|
||||
// show "what's new" button only when change list URL was not provided in results
|
||||
|
||||
Reference in New Issue
Block a user