mirror of
https://github.com/keymanapp/keyman.git
synced 2026-10-27 16:27:49 +00:00
Merge branch 'epic/windows-updates' into chore/merge-master-into-windows-updates
This commit is contained in:
commit
cb0a60a1b4
17 changed files with 810 additions and 89 deletions
|
|
@ -35,6 +35,7 @@ type
|
|||
|
||||
TUpdateCheckResponse = record
|
||||
private
|
||||
FOriginalData: string;
|
||||
FInstallSize: Int64;
|
||||
FInstallURL: string;
|
||||
FNewVersion: string;
|
||||
|
|
@ -46,9 +47,13 @@ type
|
|||
FFileName: string;
|
||||
function ParseKeyboards(nodes: TJSONObject): Boolean;
|
||||
function ParseLanguages(i: Integer; v: TJSONValue): Boolean;
|
||||
function DoParse(const message, app, currentVersion: string): Boolean;
|
||||
public
|
||||
function Parse(const message: AnsiString; const app, currentVersion: string): Boolean;
|
||||
|
||||
procedure SaveToFile(const Filename: string);
|
||||
function LoadFromFile(const Filename, app, currentVersion: string): Boolean;
|
||||
|
||||
property CurrentVersion: string read FCurrentVersion;
|
||||
property NewVersion: string read FNewVersion;
|
||||
property NewVersionWithTag: string read FNewVersionWithTag;
|
||||
|
|
@ -58,25 +63,32 @@ type
|
|||
property ErrorMessage: string read FErrorMessage;
|
||||
property Status: TUpdateCheckResponseStatus read FStatus;
|
||||
property Packages: TUpdateCheckResponsePackages read FPackages;
|
||||
property OriginalData: string read FOriginalData;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.Classes,
|
||||
System.Generics.Collections,
|
||||
versioninfo;
|
||||
|
||||
{ TUpdateCheckResponse }
|
||||
|
||||
function TUpdateCheckResponse.Parse(const message: AnsiString; const app, currentVersion: string): Boolean;
|
||||
begin
|
||||
Result := DoParse(string(UTF8String(message)), app, currentVersion);
|
||||
end;
|
||||
|
||||
function TUpdateCheckResponse.DoParse(const message, app, currentVersion: string): Boolean;
|
||||
var
|
||||
node, doc: TJSONObject;
|
||||
begin
|
||||
FOriginalData := message;
|
||||
FCurrentVersion := currentVersion;
|
||||
FStatus := ucrsNoUpdate;
|
||||
|
||||
// TODO: test with UTF8 characters in response
|
||||
doc := TJSONObject.ParseJSONValue(UTF8String(message)) as TJSONObject;
|
||||
doc := TJSONObject.ParseJSONValue(UTF8String(FOriginalData)) as TJSONObject;
|
||||
if doc = nil then
|
||||
begin
|
||||
FErrorMessage := Format('Invalid response:'#13#10'%s', [string(message)]);
|
||||
|
|
@ -168,4 +180,29 @@ begin
|
|||
Result := True;
|
||||
end;
|
||||
|
||||
function TUpdateCheckResponse.LoadFromFile(const Filename, app, currentVersion: string): Boolean;
|
||||
var
|
||||
ss: TStringStream;
|
||||
begin
|
||||
ss := TStringStream.Create('', TEncoding.UTF8);
|
||||
try
|
||||
ss.LoadFromFile(Filename);
|
||||
Result := DoParse(ss.DataString, app, currentVersion);
|
||||
finally
|
||||
ss.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TUpdateCheckResponse.SaveToFile(const Filename: string);
|
||||
var
|
||||
ss: TStringStream;
|
||||
begin
|
||||
ss := TStringStream.Create(FOriginalData, TEncoding.UTF8);
|
||||
try
|
||||
ss.SaveToFile(Filename);
|
||||
finally
|
||||
ss.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ type
|
|||
const S_CEF_SubProcess = 'kmbrowserhost.exe';
|
||||
const S_CEF_SubProcess_Developer = 'kmdbrowserhost.exe';
|
||||
const S_CustomisationFilename = 'desktop_pro.pxx';
|
||||
|
||||
const S_KeymanAppData_UpdateCache = 'Keyman\UpdateCache\';
|
||||
public
|
||||
const S_KMShell = 'kmshell.exe';
|
||||
const S_TSysInfoExe = 'tsysinfo.exe';
|
||||
|
|
@ -27,8 +29,10 @@ type
|
|||
const S_FallbackKeyboardPath = 'Keyboards\';
|
||||
const S__Package = '_Package\';
|
||||
const S_MCompileExe = 'mcompile.exe';
|
||||
const S_UpdateCache_Metadata = 'cache.json';
|
||||
class function ErrorLogPath(const app: string = ''): string; static;
|
||||
class function KeymanHelpPath(const HelpFile: string): string; static;
|
||||
class function KeymanUpdateCachePath(const filename: string = ''): string; static;
|
||||
class function KeymanDesktopInstallPath(const filename: string = ''): string; static;
|
||||
class function KeymanEngineInstallPath(const filename: string = ''): string; static;
|
||||
class function KeymanDesktopInstallDir: string; static;
|
||||
|
|
@ -423,6 +427,11 @@ begin
|
|||
Result := '';
|
||||
end;
|
||||
|
||||
class function TKeymanPaths.KeymanUpdateCachePath(const filename: string): string;
|
||||
begin
|
||||
Result := GetFolderPath(CSIDL_LOCAL_APPDATA) + S_KeymanAppData_UpdateCache + filename;
|
||||
end;
|
||||
|
||||
class function TKeymanPaths.RunningFromSource(var keyman_root: string): Boolean;
|
||||
begin
|
||||
// On developer machines, if we are running within the source repo, then use
|
||||
|
|
|
|||
|
|
@ -177,7 +177,10 @@ uses
|
|||
Keyman.Configuration.System.HttpServer.App.TextEditorFonts in 'startup\help\Keyman.Configuration.System.HttpServer.App.TextEditorFonts.pas',
|
||||
Keyman.Configuration.System.HttpServer.App.Locale in 'web\Keyman.Configuration.System.HttpServer.App.Locale.pas',
|
||||
Keyman.System.AndroidStringToKeymanLocaleString in '..\..\..\..\common\windows\delphi\general\Keyman.System.AndroidStringToKeymanLocaleString.pas',
|
||||
Keyman.Configuration.System.Main in 'main\Keyman.Configuration.System.Main.pas';
|
||||
Keyman.Configuration.System.Main in 'main\Keyman.Configuration.System.Main.pas',
|
||||
UpdateXMLRenderer in 'render\UpdateXMLRenderer.pas',
|
||||
Keyman.System.UpdateCheckStorage in 'main\Keyman.System.UpdateCheckStorage.pas',
|
||||
Keyman.System.RemoteUpdateCheck in 'main\Keyman.System.RemoteUpdateCheck.pas';
|
||||
|
||||
{$R VERSION.RES}
|
||||
{$R manifest.res}
|
||||
|
|
|
|||
|
|
@ -354,6 +354,9 @@
|
|||
<DCCReference Include="web\Keyman.Configuration.System.HttpServer.App.Locale.pas"/>
|
||||
<DCCReference Include="..\..\..\..\common\windows\delphi\general\Keyman.System.AndroidStringToKeymanLocaleString.pas"/>
|
||||
<DCCReference Include="main\Keyman.Configuration.System.Main.pas"/>
|
||||
<DCCReference Include="render\UpdateXMLRenderer.pas"/>
|
||||
<DCCReference Include="main\Keyman.System.UpdateCheckStorage.pas"/>
|
||||
<DCCReference Include="main\Keyman.System.RemoteUpdateCheck.pas"/>
|
||||
<None Include="Profiling\AQtimeModule1.aqt"/>
|
||||
<BuildConfiguration Include="Debug">
|
||||
<Key>Cfg_2</Key>
|
||||
|
|
@ -415,9 +418,9 @@
|
|||
<Platform value="Win64">False</Platform>
|
||||
</Platforms>
|
||||
<Deployment Version="3">
|
||||
<DeployFile LocalName="kmshell.rsm" Configuration="Debug" Class="DebugSymbols">
|
||||
<DeployFile LocalName="bin\Win32\Debug\kmshell.exe" Configuration="Debug" Class="ProjectOutput">
|
||||
<Platform Name="Win32">
|
||||
<RemoteName>kmshell.rsm</RemoteName>
|
||||
<RemoteName>kmshell.exe</RemoteName>
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
|
|
@ -427,9 +430,9 @@
|
|||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployFile LocalName="Profiling\AQtimeModule1.aqt" Configuration="Debug" Class="ProjectFile">
|
||||
<DeployFile LocalName="bin\Win32\Debug\kmshell.rsm" Configuration="Debug" Class="DebugSymbols">
|
||||
<Platform Name="Win32">
|
||||
<RemoteDir>.\</RemoteDir>
|
||||
<RemoteName>kmshell.rsm</RemoteName>
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,378 @@
|
|||
{
|
||||
* Keyman is copyright (C) SIL International. MIT License.
|
||||
*
|
||||
* Keyman.System.RemoteUpdateCheck: Checks for keyboard package and Keyman
|
||||
for Windows updates.
|
||||
}
|
||||
unit Keyman.System.RemoteUpdateCheck; // I3306
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.Classes,
|
||||
System.SysUtils,
|
||||
KeymanPaths,
|
||||
httpuploader,
|
||||
Keyman.System.UpdateCheckResponse,
|
||||
OnlineUpdateCheck;
|
||||
|
||||
type
|
||||
ERemoteUpdateCheck = class(Exception);
|
||||
|
||||
TRemoteUpdateCheckResult = (wucUnknown, wucSuccess, wucNoUpdates, wucFailure, wucOffline);
|
||||
|
||||
TRemoteUpdateCheckDownloadParams = record
|
||||
TotalSize: Integer;
|
||||
TotalDownloads: Integer;
|
||||
StartPosition: Integer;
|
||||
end;
|
||||
|
||||
TRemoteUpdateCheck = class
|
||||
private
|
||||
FForce: Boolean;
|
||||
FRemoteResult: TRemoteUpdateCheckResult;
|
||||
|
||||
FErrorMessage: string;
|
||||
|
||||
FShowErrors: Boolean;
|
||||
FDownload: TRemoteUpdateCheckDownloadParams;
|
||||
FCheckOnly: Boolean;
|
||||
|
||||
function DownloadUpdates(Params: TUpdateCheckResponse) : Boolean;
|
||||
procedure DoDownloadUpdates(SavePath: string; Params: TUpdateCheckResponse; var Result: Boolean);
|
||||
function DoRun: TRemoteUpdateCheckResult;
|
||||
public
|
||||
|
||||
constructor Create(AForce : Boolean; ACheckOnly: Boolean = False);
|
||||
destructor Destroy; override;
|
||||
function Run: TRemoteUpdateCheckResult;
|
||||
property ShowErrors: Boolean read FShowErrors write FShowErrors;
|
||||
end;
|
||||
|
||||
procedure LogMessage(LogMessage: string);
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.WideStrUtils,
|
||||
Winapi.Windows,
|
||||
Winapi.WinINet,
|
||||
|
||||
GlobalProxySettings,
|
||||
KLog,
|
||||
keymanapi_TLB,
|
||||
KeymanVersion,
|
||||
Keyman.System.UpdateCheckStorage,
|
||||
kmint,
|
||||
ErrorControlledRegistry,
|
||||
RegistryKeys,
|
||||
Upload_Settings,
|
||||
|
||||
OnlineUpdateCheckMessages;
|
||||
|
||||
{ TRemoteUpdateCheck }
|
||||
|
||||
constructor TRemoteUpdateCheck.Create(AForce, ACheckOnly: Boolean);
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
FShowErrors := True;
|
||||
FRemoteResult := wucUnknown;
|
||||
|
||||
FForce := AForce;
|
||||
FCheckOnly := ACheckOnly;
|
||||
|
||||
KL.Log('TRemoteUpdateCheck.Create');
|
||||
end;
|
||||
|
||||
destructor TRemoteUpdateCheck.Destroy;
|
||||
begin
|
||||
if (FErrorMessage <> '') and FShowErrors then
|
||||
LogMessage(FErrorMessage);
|
||||
|
||||
KL.Log('TRemoteUpdateCheck.Destroy: FErrorMessage = '+FErrorMessage);
|
||||
KL.Log('TRemoteUpdateCheck.Destroy: FRemoteResult = '+IntToStr(Ord(FRemoteResult)));
|
||||
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TRemoteUpdateCheck.Run: TRemoteUpdateCheckResult;
|
||||
begin
|
||||
Result := DoRun;
|
||||
|
||||
if Result in [ wucSuccess] then
|
||||
begin
|
||||
kmcom.Keyboards.Refresh;
|
||||
kmcom.Keyboards.Apply;
|
||||
kmcom.Packages.Refresh;
|
||||
end;
|
||||
|
||||
FRemoteResult := Result;
|
||||
end;
|
||||
|
||||
|
||||
procedure TRemoteUpdateCheck.DoDownloadUpdates(SavePath: string; Params: TUpdateCheckResponse; var Result: Boolean);
|
||||
var
|
||||
i, downloadCount: Integer;
|
||||
http: THttpUploader;
|
||||
fs: TFileStream;
|
||||
|
||||
function DownloadFile(const url, savepath: string): Boolean;
|
||||
begin
|
||||
try
|
||||
http := THttpUploader.Create(nil);
|
||||
try
|
||||
http.Proxy.Server := GetProxySettings.Server;
|
||||
http.Proxy.Port := GetProxySettings.Port;
|
||||
http.Proxy.Username := GetProxySettings.Username;
|
||||
http.Proxy.Password := GetProxySettings.Password;
|
||||
http.Request.Agent := API_UserAgent;
|
||||
|
||||
http.Request.SetURL(url);
|
||||
http.Upload;
|
||||
if http.Response.StatusCode = 200 then
|
||||
begin
|
||||
fs := TFileStream.Create(savepath, fmCreate);
|
||||
try
|
||||
fs.Write(http.Response.PMessageBody^, http.Response.MessageBodyLength);
|
||||
finally
|
||||
fs.Free;
|
||||
end;
|
||||
Result := True;
|
||||
end
|
||||
else // I2742
|
||||
// If it fails we set to false but will try the other files
|
||||
Result := False;
|
||||
Exit;
|
||||
finally
|
||||
http.Free;
|
||||
end;
|
||||
except
|
||||
on E:EHTTPUploader do
|
||||
begin
|
||||
if (E.ErrorCode = 12007) or (E.ErrorCode = 12029)
|
||||
then LogMessage(S_OnlineUpdate_UnableToContact)
|
||||
else LogMessage(WideFormat(S_OnlineUpdate_UnableToContact_Error, [E.Message]));
|
||||
Result := False;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
Result := False;
|
||||
|
||||
FDownload.TotalSize := 0;
|
||||
FDownload.TotalDownloads := 0;
|
||||
downloadCount := 0;
|
||||
|
||||
// Keyboard Packages
|
||||
for i := 0 to High(Params.Packages) do
|
||||
begin
|
||||
Inc(FDownload.TotalDownloads);
|
||||
Inc(FDownload.TotalSize, Params.Packages[i].DownloadSize);
|
||||
Params.Packages[i].SavePath := SavePath + Params.Packages[i].FileName;
|
||||
end;
|
||||
|
||||
// Add the Keyman installer
|
||||
Inc(FDownload.TotalDownloads);
|
||||
Inc(FDownload.TotalSize, Params.InstallSize);
|
||||
|
||||
// Keyboard Packages
|
||||
FDownload.StartPosition := 0;
|
||||
for i := 0 to High(Params.Packages) do
|
||||
begin
|
||||
if not DownloadFile(Params.Packages[i].DownloadURL, Params.Packages[i].SavePath) then // I2742
|
||||
begin
|
||||
Params.Packages[i].Install := False; // Download failed but install other files
|
||||
end
|
||||
else
|
||||
Inc(downloadCount);
|
||||
FDownload.StartPosition := FDownload.StartPosition + Params.Packages[i].DownloadSize;
|
||||
end;
|
||||
|
||||
// Keyman Installer
|
||||
if not DownloadFile(Params.InstallURL, SavePath + Params.FileName) then // I2742
|
||||
begin
|
||||
// TODO: #10210record fail? and log // Download failed but user wants to install other files
|
||||
end
|
||||
else
|
||||
begin
|
||||
Inc(downloadCount)
|
||||
end;
|
||||
|
||||
// There needs to be at least one file successfully downloaded to return
|
||||
// True that files were downloaded
|
||||
if downloadCount > 0 then
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function TRemoteUpdateCheck.DownloadUpdates(Params: TUpdateCheckResponse): Boolean;
|
||||
var
|
||||
DownloadBackGroundSavePath : String;
|
||||
DownloadResult : Boolean;
|
||||
begin
|
||||
DownloadBackGroundSavePath := IncludeTrailingPathDelimiter(TKeymanPaths.KeymanUpdateCachePath);
|
||||
|
||||
DoDownloadUpdates(DownloadBackGroundSavePath, Params, DownloadResult);
|
||||
KL.Log('TRemoteUpdateCheck.DownloadUpdatesBackground: DownloadResult = '+IntToStr(Ord(DownloadResult)));
|
||||
Result := DownloadResult;
|
||||
|
||||
end;
|
||||
|
||||
function TRemoteUpdateCheck.DoRun: TRemoteUpdateCheckResult;
|
||||
var
|
||||
flags: DWord;
|
||||
i: Integer;
|
||||
ucr: TUpdateCheckResponse;
|
||||
pkg: IKeymanPackage;
|
||||
downloadResult: boolean;
|
||||
registry: TRegistryErrorControlled;
|
||||
http: THttpUploader;
|
||||
begin
|
||||
{FProxyHost := '';
|
||||
FProxyPort := 0;}
|
||||
|
||||
{ Check if user is currently online }
|
||||
if not InternetGetConnectedState(@flags, 0) then
|
||||
begin
|
||||
Result := wucOffline;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
{ Verify that it has been at least 7 days since last update check }
|
||||
try
|
||||
registry := TRegistryErrorControlled.Create; // I2890
|
||||
try
|
||||
if registry.OpenKeyReadOnly(SRegKey_KeymanDesktop_CU) then
|
||||
begin
|
||||
if registry.ValueExists(SRegValue_CheckForUpdates) and not registry.ReadBool(SRegValue_CheckForUpdates) and not FForce then
|
||||
begin
|
||||
Result := wucNoUpdates;
|
||||
Exit;
|
||||
end;
|
||||
if registry.ValueExists(SRegValue_LastUpdateCheckTime) and (Now - registry.ReadDateTime(SRegValue_LastUpdateCheckTime) < 7) and not FForce then
|
||||
begin
|
||||
Result := wucNoUpdates;
|
||||
// TODO: #10210 This exit is just to remove the time check for testing.
|
||||
//Exit;
|
||||
end;
|
||||
|
||||
{if ValueExists(SRegValue_UpdateCheck_UseProxy) and ReadBool(SRegValue_UpdateCheck_UseProxy) then
|
||||
begin
|
||||
FProxyHost := ReadString(SRegValue_UpdateCheck_ProxyHost);
|
||||
FProxyPort := StrToIntDef(ReadString(SRegValue_UpdateCheck_ProxyPort), 80);
|
||||
end;}
|
||||
end;
|
||||
finally
|
||||
registry.Free;
|
||||
end;
|
||||
except
|
||||
{ we will not run the check if an error occurs reading the settings }
|
||||
on E:Exception do
|
||||
begin
|
||||
Result := wucFailure;
|
||||
FErrorMessage := E.Message;
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
Result := wucNoUpdates;
|
||||
|
||||
try
|
||||
http := THTTPUploader.Create(nil);
|
||||
try
|
||||
http.Fields.Add('version', ansistring(CKeymanVersionInfo.Version));
|
||||
http.Fields.Add('tier', ansistring(CKeymanVersionInfo.Tier));
|
||||
if FForce
|
||||
then http.Fields.Add('manual', '1')
|
||||
else http.Fields.Add('manual', '0');
|
||||
|
||||
for i := 0 to kmcom.Packages.Count - 1 do
|
||||
begin
|
||||
pkg := kmcom.Packages[i];
|
||||
|
||||
// Due to limitations in PHP parsing of query string parameters names with
|
||||
// space or period, we need to split the parameters up. The legacy pattern
|
||||
// is still supported on the server side. Relates to #4886.
|
||||
http.Fields.Add(AnsiString('packageid_'+IntToStr(i)), AnsiString(pkg.ID));
|
||||
http.Fields.Add(AnsiString('packageversion_'+IntToStr(i)), AnsiString(pkg.Version));
|
||||
pkg := nil;
|
||||
end;
|
||||
|
||||
http.Proxy.Server := GetProxySettings.Server;
|
||||
http.Proxy.Port := GetProxySettings.Port;
|
||||
http.Proxy.Username := GetProxySettings.Username;
|
||||
http.Proxy.Password := GetProxySettings.Password;
|
||||
|
||||
http.Request.HostName := API_Server;
|
||||
http.Request.Protocol := API_Protocol;
|
||||
http.Request.UrlPath := API_Path_UpdateCheck_Windows;
|
||||
//OnStatus :=
|
||||
http.Upload;
|
||||
if http.Response.StatusCode = 200 then
|
||||
begin
|
||||
if ucr.Parse(http.Response.MessageBodyAsString, 'bundle', CKeymanVersionInfo.Version) then
|
||||
begin
|
||||
//ResponseToParams(ucr);
|
||||
|
||||
if FCheckOnly then
|
||||
begin
|
||||
TUpdateCheckStorage.SaveUpdateCacheData(ucr);
|
||||
Result := FRemoteResult;
|
||||
end
|
||||
// TODO: ##10210
|
||||
// Integerate into state machine. in the download state
|
||||
// the process can call LoadUpdateCacheData if needed to get the
|
||||
// response result.
|
||||
else if (Length(ucr.Packages) > 0) or (ucr.InstallURL <> '') then
|
||||
begin
|
||||
downloadResult := DownloadUpdates(ucr);
|
||||
if DownloadResult then
|
||||
begin
|
||||
Result := wucSuccess;
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
FErrorMessage := ucr.ErrorMessage;
|
||||
Result := wucFailure;
|
||||
end;
|
||||
end
|
||||
else
|
||||
raise ERemoteUpdateCheck.Create('Error '+IntToStr(http.Response.StatusCode));
|
||||
finally
|
||||
http.Free;
|
||||
end;
|
||||
except
|
||||
on E:EHTTPUploader do
|
||||
begin
|
||||
if (E.ErrorCode = 12007) or (E.ErrorCode = 12029)
|
||||
then FErrorMessage := S_OnlineUpdate_UnableToContact
|
||||
else FErrorMessage := WideFormat(S_OnlineUpdate_UnableToContact_Error, [E.Message]);
|
||||
Result := wucFailure;
|
||||
end;
|
||||
on E:Exception do
|
||||
begin
|
||||
FErrorMessage := E.Message;
|
||||
Result := wucFailure;
|
||||
end;
|
||||
end;
|
||||
|
||||
registry := TRegistryErrorControlled.Create; // I2890
|
||||
try
|
||||
if registry.OpenKey(SRegKey_KeymanDesktop_CU, True) then
|
||||
registry.WriteDateTime(SRegValue_LastUpdateCheckTime, Now);
|
||||
finally
|
||||
registry.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
// temp wrapper for converting showmessage to logs don't know where
|
||||
// if nt using klog
|
||||
procedure LogMessage(LogMessage: string);
|
||||
begin
|
||||
KL.Log(LogMessage);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
unit Keyman.System.UpdateCheckStorage;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Keyman.System.UpdateCheckResponse;
|
||||
|
||||
type
|
||||
TUpdateCheckStorage = class sealed
|
||||
private
|
||||
class function MetadataFilename: string; static;
|
||||
public
|
||||
class function HasUpdates: Boolean; static;
|
||||
class function LoadUpdateCacheData(var data: TUpdateCheckResponse): Boolean; static;
|
||||
class procedure SaveUpdateCacheData(const data: TUpdateCheckResponse); static;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
|
||||
KeymanPaths,
|
||||
KeymanVersion;
|
||||
|
||||
{ TUpdateCheckStorage }
|
||||
|
||||
class function TUpdateCheckStorage.MetadataFilename: string;
|
||||
begin
|
||||
Result := TKeymanPaths.KeymanUpdateCachePath(TKeymanPaths.S_UpdateCache_Metadata);
|
||||
end;
|
||||
|
||||
class procedure TUpdateCheckStorage.SaveUpdateCacheData(
|
||||
const data: TUpdateCheckResponse);
|
||||
begin
|
||||
ForceDirectories(TKeymanPaths.KeymanUpdateCachePath);
|
||||
data.SaveToFile(MetadataFilename);
|
||||
end;
|
||||
|
||||
class function TUpdateCheckStorage.HasUpdates: Boolean;
|
||||
begin
|
||||
Result := FileExists(MetadataFilename);
|
||||
end;
|
||||
|
||||
class function TUpdateCheckStorage.LoadUpdateCacheData(var data: TUpdateCheckResponse): Boolean;
|
||||
begin
|
||||
Result :=
|
||||
HasUpdates and
|
||||
data.LoadFromFile(MetadataFilename, 'bundle', CKeymanVersionInfo.Version);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
@ -98,6 +98,7 @@ type
|
|||
|
||||
FShowErrors: Boolean;
|
||||
FDownload: TOnlineUpdateCheckDownloadParams;
|
||||
FCheckOnly: Boolean;
|
||||
|
||||
function DownloadUpdates: Boolean;
|
||||
procedure DoDownloadUpdates(AOwner: TfrmDownloadProgress; var Result: Boolean);
|
||||
|
|
@ -112,7 +113,9 @@ type
|
|||
public
|
||||
|
||||
public
|
||||
constructor Create(AOwner: TCustomForm; AForce, ASilent: Boolean);
|
||||
function ResponseToParams(const ucr: TUpdateCheckResponse): TOnlineUpdateCheckParams;
|
||||
|
||||
constructor Create(AOwner: TCustomForm; AForce, ASilent: Boolean; ACheckOnly: Boolean = False);
|
||||
destructor Destroy; override;
|
||||
function Run: TOnlineUpdateCheckResult;
|
||||
property ShowErrors: Boolean read FShowErrors write FShowErrors;
|
||||
|
|
@ -146,6 +149,7 @@ uses
|
|||
KLog,
|
||||
keymanapi_TLB,
|
||||
KeymanVersion,
|
||||
Keyman.System.UpdateCheckStorage,
|
||||
kmint,
|
||||
ErrorControlledRegistry,
|
||||
RegistryKeys,
|
||||
|
|
@ -165,7 +169,7 @@ const
|
|||
|
||||
{ TOnlineUpdateCheck }
|
||||
|
||||
constructor TOnlineUpdateCheck.Create(AOwner: TCustomForm; AForce, ASilent: Boolean);
|
||||
constructor TOnlineUpdateCheck.Create(AOwner: TCustomForm; AForce, ASilent: Boolean; ACheckOnly: Boolean);
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
|
|
@ -176,6 +180,7 @@ begin
|
|||
|
||||
FSilent := ASilent;
|
||||
FForce := AForce;
|
||||
FCheckOnly := ACheckOnly;
|
||||
|
||||
KL.Log('TOnlineUpdateCheck.Create');
|
||||
end;
|
||||
|
|
@ -477,10 +482,9 @@ end;
|
|||
function TOnlineUpdateCheck.DoRun: TOnlineUpdateCheckResult;
|
||||
var
|
||||
flags: DWord;
|
||||
i, n: Integer;
|
||||
pkg: IKeymanPackage;
|
||||
j: Integer;
|
||||
i: Integer;
|
||||
ucr: TUpdateCheckResponse;
|
||||
pkg: IKeymanPackage;
|
||||
begin
|
||||
{FProxyHost := '';
|
||||
FProxyPort := 0;}
|
||||
|
|
@ -567,45 +571,15 @@ begin
|
|||
begin
|
||||
if ucr.Parse(Response.MessageBodyAsString, 'bundle', CKeymanVersionInfo.Version) then
|
||||
begin
|
||||
SetLength(FParams.Packages,0);
|
||||
for i := Low(ucr.Packages) to High(ucr.Packages) do
|
||||
ResponseToParams(ucr);
|
||||
|
||||
if FCheckOnly then
|
||||
begin
|
||||
n := kmcom.Packages.IndexOf(ucr.Packages[i].ID);
|
||||
if n >= 0 then
|
||||
begin
|
||||
pkg := kmcom.Packages[n];
|
||||
j := Length(FParams.Packages);
|
||||
SetLength(FParams.Packages, j+1);
|
||||
FParams.Packages[j].NewID := ucr.Packages[i].NewID;
|
||||
FParams.Packages[j].ID := ucr.Packages[i].ID;
|
||||
FParams.Packages[j].Description := ucr.Packages[i].Name;
|
||||
FParams.Packages[j].OldVersion := pkg.Version;
|
||||
FParams.Packages[j].NewVersion := ucr.Packages[i].NewVersion;
|
||||
FParams.Packages[j].DownloadSize := ucr.Packages[i].DownloadSize;
|
||||
FParams.Packages[j].DownloadURL := ucr.Packages[i].DownloadURL;
|
||||
FParams.Packages[j].FileName := ucr.Packages[i].FileName;
|
||||
pkg := nil;
|
||||
end
|
||||
else
|
||||
FErrorMessage := 'Unable to find package '+ucr.Packages[i].ID;
|
||||
end;
|
||||
|
||||
case ucr.Status of
|
||||
ucrsNoUpdate:
|
||||
begin
|
||||
FErrorMessage := ucr.ErrorMessage;
|
||||
end;
|
||||
ucrsUpdateReady:
|
||||
begin
|
||||
FParams.Keyman.OldVersion := ucr.CurrentVersion;
|
||||
FParams.Keyman.NewVersion := ucr.NewVersion;
|
||||
FParams.Keyman.DownloadURL := ucr.InstallURL;
|
||||
FParams.Keyman.DownloadSize := ucr.InstallSize;
|
||||
FParams.Keyman.FileName := ucr.FileName;
|
||||
end;
|
||||
end;
|
||||
|
||||
if (Length(FParams.Packages) > 0) or (FParams.Keyman.DownloadURL <> '') then
|
||||
// TODO: Refactor this
|
||||
TUpdateCheckStorage.SaveUpdateCacheData(ucr);
|
||||
Result := FParams.Result;
|
||||
end
|
||||
else if (Length(FParams.Packages) > 0) or (FParams.Keyman.DownloadURL <> '') then
|
||||
begin
|
||||
if not FSilent then
|
||||
ShowUpdateForm
|
||||
|
|
@ -651,6 +625,52 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
function TOnlineUpdateCheck.ResponseToParams(const ucr: TUpdateCheckResponse): TOnlineUpdateCheckParams;
|
||||
var
|
||||
i, j, n: Integer;
|
||||
pkg: IKeymanPackage;
|
||||
begin
|
||||
SetLength(FParams.Packages,0);
|
||||
for i := Low(ucr.Packages) to High(ucr.Packages) do
|
||||
begin
|
||||
n := kmcom.Packages.IndexOf(ucr.Packages[i].ID);
|
||||
if n >= 0 then
|
||||
begin
|
||||
pkg := kmcom.Packages[n];
|
||||
j := Length(FParams.Packages);
|
||||
SetLength(FParams.Packages, j+1);
|
||||
FParams.Packages[j].NewID := ucr.Packages[i].NewID;
|
||||
FParams.Packages[j].ID := ucr.Packages[i].ID;
|
||||
FParams.Packages[j].Description := ucr.Packages[i].Name;
|
||||
FParams.Packages[j].OldVersion := pkg.Version;
|
||||
FParams.Packages[j].NewVersion := ucr.Packages[i].NewVersion;
|
||||
FParams.Packages[j].DownloadSize := ucr.Packages[i].DownloadSize;
|
||||
FParams.Packages[j].DownloadURL := ucr.Packages[i].DownloadURL;
|
||||
FParams.Packages[j].FileName := ucr.Packages[i].FileName;
|
||||
pkg := nil;
|
||||
end
|
||||
else
|
||||
FErrorMessage := 'Unable to find package '+ucr.Packages[i].ID;
|
||||
end;
|
||||
|
||||
case ucr.Status of
|
||||
ucrsNoUpdate:
|
||||
begin
|
||||
FErrorMessage := ucr.ErrorMessage;
|
||||
end;
|
||||
ucrsUpdateReady:
|
||||
begin
|
||||
FParams.Keyman.OldVersion := ucr.CurrentVersion;
|
||||
FParams.Keyman.NewVersion := ucr.NewVersion;
|
||||
FParams.Keyman.DownloadURL := ucr.InstallURL;
|
||||
FParams.Keyman.DownloadSize := ucr.InstallSize;
|
||||
FParams.Keyman.FileName := ucr.FileName;
|
||||
end;
|
||||
end;
|
||||
|
||||
Result := FParams;
|
||||
end;
|
||||
|
||||
procedure OnlineUpdateAdmin(OwnerForm: TCustomForm; Path: string);
|
||||
var
|
||||
Package: TOnlineUpdateCheckParamsPackage;
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ type
|
|||
procedure OpenSite(params: TStringList);
|
||||
procedure DoApply;
|
||||
procedure DoRefresh;
|
||||
procedure Update_CheckNow;
|
||||
|
||||
protected
|
||||
procedure FireCommand(const command: WideString; params: TStringList); override;
|
||||
|
|
@ -202,6 +203,7 @@ uses
|
|||
UfrmTextEditor,
|
||||
uninstall,
|
||||
Upload_Settings,
|
||||
UpdateXMLRenderer,
|
||||
utildir,
|
||||
utilexecute,
|
||||
utilkmshell,
|
||||
|
|
@ -301,6 +303,7 @@ begin
|
|||
FXMLRenderers.Add(TOptionsXMLRenderer.Create(FXMLRenderers));
|
||||
FXMLRenderers.Add(TLanguagesXMLRenderer.Create(FXMLRenderers));
|
||||
FXMLRenderers.Add(TSupportXMLRenderer.Create(FXMLRenderers));
|
||||
FXMLRenderers.Add(TUpdateXMLRenderer.Create(FXMLRenderers));
|
||||
|
||||
xml := FXMLRenderers.RenderToString(s);
|
||||
sharedData.Init(
|
||||
|
|
@ -345,6 +348,8 @@ begin
|
|||
else if command = 'support_updatecheck' then Support_UpdateCheck
|
||||
else if command = 'support_proxyconfig' then Support_ProxyConfig
|
||||
|
||||
else if command = 'update_checknow' then Update_CheckNow
|
||||
|
||||
else if command = 'contact_support' then Support_ContactSupport(params) // I4390
|
||||
|
||||
else if command = 'opensite' then OpenSite(params)
|
||||
|
|
@ -815,6 +820,17 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
procedure TfrmMain.Update_CheckNow;
|
||||
begin
|
||||
with TOnlineUpdateCheck.Create(Self, True, True, True) do
|
||||
try
|
||||
Run;
|
||||
finally
|
||||
Free;
|
||||
end;
|
||||
DoRefresh;
|
||||
end;
|
||||
|
||||
procedure TfrmMain.TntFormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
||||
begin
|
||||
inherited;
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ type
|
|||
fmMigrate, fmSplash, fmStart,
|
||||
fmUpgradeKeyboards, fmOnlineUpdateCheck,// I2548
|
||||
fmOnlineUpdateAdmin, fmTextEditor,
|
||||
fmBackgroundUpdateCheck,
|
||||
fmFirstRun, // I2562
|
||||
fmKeyboardWelcome, // I2569
|
||||
fmKeyboardPrint, // I2329
|
||||
|
|
@ -120,6 +121,7 @@ uses
|
|||
KMShellHints,
|
||||
KeymanMutex,
|
||||
OnlineUpdateCheck,
|
||||
Keyman.System.RemoteUpdateCheck,
|
||||
RegistryKeys,
|
||||
UfrmBaseKeyboard,
|
||||
UfrmKeymanBase,
|
||||
|
|
@ -249,6 +251,7 @@ begin
|
|||
else if s = '-h' then FMode := fmHelp
|
||||
else if s = '-t' then FMode := fmTextEditor
|
||||
else if s = '-ouc' then FMode := fmOnlineUpdateCheck
|
||||
else if s = '-buc' then FMode := fmBackgroundUpdateCheck
|
||||
else if s = '-basekeyboard' then FMode := fmBaseKeyboard // I4169
|
||||
else if s = '-nowelcome' then FNoWelcome := True
|
||||
else if s = '-kw' then FMode := fmKeyboardWelcome // I2569
|
||||
|
|
@ -381,6 +384,7 @@ var
|
|||
kdl: IKeymanDefaultLanguage;
|
||||
FIcon: string;
|
||||
FMutex: TKeymanMutex; // I2720
|
||||
RemoteUpdateCheck: TRemoteUpdateCheck;
|
||||
function FirstKeyboardFileName: WideString;
|
||||
begin
|
||||
if KeyboardFileNames.Count = 0
|
||||
|
|
@ -427,6 +431,19 @@ begin
|
|||
ShowMessage(MsgFromId(SKOSNotSupported));
|
||||
Exit;
|
||||
end;
|
||||
// TODO: #10038 Will add this as part of the background update state machine
|
||||
// for now just verifing the download happens via -buc switch.
|
||||
RemoteUpdateCheck := TRemoteUpdateCheck.Create(False, False);
|
||||
try
|
||||
if (FMode = fmBackgroundUpdateCheck) then
|
||||
begin
|
||||
RemoteUpdateCheck.Run;
|
||||
Exit;
|
||||
end
|
||||
finally
|
||||
RemoteUpdateCheck.Free;
|
||||
end;
|
||||
|
||||
|
||||
if not FSilent or (FMode = fmUpgradeMnemonicLayout) then // I4553
|
||||
begin
|
||||
|
|
|
|||
93
windows/src/desktop/kmshell/render/UpdateXMLRenderer.pas
Normal file
93
windows/src/desktop/kmshell/render/UpdateXMLRenderer.pas
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
(*
|
||||
Name: UpdateXMLRenderer
|
||||
Copyright: Copyright (C) SIL International.
|
||||
*)
|
||||
unit UpdateXMLRenderer;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
XMLRenderer,
|
||||
Windows;
|
||||
|
||||
type
|
||||
TUpdateXMLRenderer = class(TXMLRenderer)
|
||||
protected
|
||||
function XMLData: WideString; override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
StrUtils,
|
||||
SysUtils,
|
||||
VersionInfo,
|
||||
kmint,
|
||||
KeymanVersion,
|
||||
keymanapi_TLB,
|
||||
Keyman.System.LocaleStrings,
|
||||
Keyman.System.UpdateCheckResponse,
|
||||
Keyman.System.UpdateCheckStorage,
|
||||
MessageIdentifierConsts,
|
||||
MessageIdentifiers,
|
||||
utilxml;
|
||||
|
||||
{ TUpdateXMLRenderer }
|
||||
|
||||
function TUpdateXMLRenderer.XMLData: WideString;
|
||||
var
|
||||
xml: string;
|
||||
ucr: TUpdateCheckResponse;
|
||||
i, n : Integer;
|
||||
pkg: IKeymanPackage;
|
||||
begin
|
||||
xml := '';
|
||||
|
||||
if TUpdateCheckStorage.LoadUpdateCacheData(ucr) then
|
||||
begin
|
||||
if (ucr.InstallURL <> '') then
|
||||
begin
|
||||
xml := xml +
|
||||
'<Update>'+
|
||||
'<index>0</index>'+
|
||||
IfThen(not kmcom.SystemInfo.IsAdministrator, '<RequiresAdmin />')+
|
||||
'<Keyman>'+
|
||||
'<Text>'+xmlencode(TLocaleStrings.MsgFromIdFormat(kmcom, SKUpdate_KeymanText, [ucr.NewVersion]))+'</Text>'+
|
||||
'<NewVersion>'+xmlencode(ucr.NewVersion)+'</NewVersion>'+
|
||||
'<OldVersion>'+xmlencode(ucr.CurrentVersion)+'</OldVersion>'+
|
||||
'<DownloadSize>'+xmlencode(Format('%d', [ucr.InstallSize div 1024]))+'KB</DownloadSize>'+
|
||||
'<DownloadURL>'+xmlencode(ucr.InstallURL)+'</DownloadURL>'+
|
||||
'</Keyman>'+
|
||||
'</Update>';
|
||||
end;
|
||||
|
||||
for i := 0 to High(ucr.Packages) do
|
||||
begin
|
||||
n := kmcom.Packages.IndexOf(ucr.Packages[i].ID);
|
||||
if n >= 0 then
|
||||
pkg := kmcom.Packages[n];
|
||||
begin
|
||||
xml := xml +
|
||||
'<Update>'+
|
||||
'<index>'+IntToStr(i+1)+'</index>'+
|
||||
IfThen(not kmcom.SystemInfo.IsAdministrator, '<RequiresAdmin />')+
|
||||
'<Package>'+
|
||||
'<Text>'+xmlencode(TLocaleStrings.MsgFromIdFormat(kmcom, SKUpdate_PackageText,
|
||||
[ucr.Packages[i].Name, ucr.Packages[i].NewVersion]))+'</Text>'+
|
||||
'<NewVersion>'+xmlencode(ucr.Packages[i].NewVersion)+'</NewVersion>'+
|
||||
'<OldVersion>'+xmlencode(pkg.version)+'</OldVersion>'+
|
||||
'<DownloadSize>'+xmlencode(Format('%d', [ucr.Packages[i].DownloadSize div 1024]))+'KB</DownloadSize>'+
|
||||
'<DownloadURL>'+xmlencode(ucr.Packages[i].DownloadURL)+'</DownloadURL>'+
|
||||
'</Package>'+
|
||||
'</Update>';
|
||||
pkg := nil;
|
||||
end;
|
||||
// else Package not found, skip
|
||||
end;
|
||||
end;
|
||||
|
||||
Result := '<Updates>'+xml+'</Updates>';
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
|
@ -1093,19 +1093,11 @@ th
|
|||
height: 16px;
|
||||
}
|
||||
|
||||
#keepintouch_content {
|
||||
#update_content {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#keepintouch_frame {
|
||||
box-sizing: border-box;
|
||||
width:100%;
|
||||
height:100%;
|
||||
border:none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* QRCodes */
|
||||
|
||||
.qrcode {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ function windowResize()
|
|||
e = _$('subcontent_pro');
|
||||
if(e) e.style.height = h;
|
||||
_$('subcontent_support').style.height = h;
|
||||
_$('subcontent_keepintouch').style.height = h;
|
||||
_$('subcontent_update').style.height = h;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
<xsl:include href="keyman_options.xsl"/>
|
||||
<xsl:include href="keyman_hotkeys.xsl"/>
|
||||
<xsl:include href="keyman_support.xsl"/>
|
||||
<xsl:include href="keyman_keepintouch.xsl"/>
|
||||
<xsl:include href="keyman_update.xsl"/>
|
||||
|
||||
<xsl:include href="keyman_footer.xsl"/>
|
||||
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
<div class="contentpage" id="content_options"><xsl:call-template name="content_options" /></div>
|
||||
<div class="contentpage" id="content_hotkeys"><xsl:call-template name="content_hotkeys" /></div>
|
||||
<div class="contentpage" id="content_support"><xsl:call-template name="content_support" /></div>
|
||||
<div class="contentpage" id="content_keepintouch"><xsl:call-template name="content_keepintouch" /></div>
|
||||
<div class="contentpage" id="content_update"><xsl:call-template name="content_update" /></div>
|
||||
</div>
|
||||
<div id="footerframe">
|
||||
<xsl:call-template name="footerframe" />
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:template name="content_keepintouch">
|
||||
|
||||
<script>
|
||||
window['menuframe_activate_keepintouch'] = function() {
|
||||
document.getElementById('keepintouch_frame').src = '<xsl:value-of select='/Keyman/keyman-com' />/go/windows/<xsl:value-of select="/Keyman/version-info/@versionRelease" />/keep-in-touch?embed=1';
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="header">
|
||||
<xsl:call-template name="header_helplinks" />
|
||||
<xsl:value-of select="$locale/string[@name='S_KeepInTouch']"/>
|
||||
</div>
|
||||
|
||||
<div id="subcontent_keepintouch" class="content">
|
||||
<div id="keepintouch_content">
|
||||
<iframe id='keepintouch_frame'></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
|
|
@ -9,20 +9,20 @@
|
|||
<xsl:variable name="locale_Options"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Options']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_Hotkeys"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Hotkeys']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_Support"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Support']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_KeepInTouch"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_KeepInTouch']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_Update"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Update']" /></xsl:call-template></xsl:variable>
|
||||
|
||||
<xsl:variable name="locale_Keyboards_AccessChar"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Keyboards_AccessChar']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_Options_AccessChar"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Options_AccessChar']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_Hotkeys_AccessChar"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Hotkeys_AccessChar']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_Support_AccessChar"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Support_AccessChar']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_KeepInTouch_AccessChar"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_KeepInTouch_AccessChar']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_Update_AccessChar"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Update_AccessChar']" /></xsl:call-template></xsl:variable>
|
||||
|
||||
<script type="text/javascript">
|
||||
menuframe_add('/app/', 'keyboardlist', '<xsl:value-of select="$locale_Keyboards"/>', '<xsl:value-of select="$locale_Keyboards_AccessChar"/>');
|
||||
menuframe_add('/app/', 'options', '<xsl:value-of select="$locale_Options"/>', '<xsl:value-of select="$locale_Options_AccessChar"/>');
|
||||
menuframe_add('/app/', 'hotkeys', '<xsl:value-of select="$locale_Hotkeys"/>', '<xsl:value-of select="$locale_Hotkeys_AccessChar"/>');
|
||||
menuframe_add('/app/', 'support', '<xsl:value-of select="$locale_Support"/>', '<xsl:value-of select="$locale_Support_AccessChar"/>');
|
||||
menuframe_add('/app/', 'keepintouch', '<xsl:value-of select="$locale_KeepInTouch"/>', '<xsl:value-of select="$locale_KeepInTouch_AccessChar"/>');
|
||||
menuframe_add('/app/', 'update', '<xsl:value-of select="$locale_Update"/>', '<xsl:value-of select="$locale_Update_AccessChar"/>');
|
||||
</script>
|
||||
<span class="menuframe" id="menuframe_footer"><xsl:text></xsl:text></span>
|
||||
</xsl:template>
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@
|
|||
<ul>
|
||||
<li><a><xsl:attribute name="href">keyman:link?url=<xsl:value-of select="/Keyman/keyman-com"/>/</xsl:attribute>keyman.com</a></li>
|
||||
<li><a href="keyman:support_diagnostics"><xsl:value-of select="$locale/string[@name='S_Menu_Diagnostics_Diagnostics']"/></a></li>
|
||||
<li><a href="keyman:support_updatecheck"><xsl:value-of select="$locale/string[@name='S_Button_CheckForUpdates']"/></a></li>
|
||||
<li><a>
|
||||
<xsl:attribute name="href">keyman:link?url=<xsl:value-of select="/Keyman/keyman-com" />/go/<xsl:value-of select="/Keyman/version-info/@versionRelease" />/support</xsl:attribute
|
||||
><xsl:value-of select="$locale/string[@name='S_Button_OnlineSupport']"/></a></li>
|
||||
|
|
|
|||
125
windows/src/desktop/kmshell/xml/keyman_update.xsl
Normal file
125
windows/src/desktop/kmshell/xml/keyman_update.xsl
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:template name="content_update">
|
||||
|
||||
<script>
|
||||
window['menuframe_activate_update'] = function() {
|
||||
document.getElementById('update_frame').src = '<xsl:value-of select='/Keyman/keyman-com' />/go/windows/<xsl:value-of select="/Keyman/version-info/@versionRelease" />/keep-in-touch?embed=1';
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="header">
|
||||
<xsl:call-template name="header_helplinks" />
|
||||
<xsl:value-of select="$locale/string[@name='S_Update']"/>
|
||||
</div>
|
||||
|
||||
<div id="subcontent_update" class="content">
|
||||
<div id="update_content">
|
||||
|
||||
<div class="update_title">
|
||||
<img src="/app/keyman-desktop.png" />
|
||||
</div>
|
||||
|
||||
<div class="update_edition">
|
||||
<xsl:value-of select="$locale/string[@name='S_Support_Version']"/> <xsl:value-of select="/Keyman/version-info/@versionWithTag" /><br />
|
||||
</div>
|
||||
|
||||
<div id="update_status">Updates are available which will be applied when Windows is next restarted:</div>
|
||||
|
||||
<div id="update_details">
|
||||
|
||||
<table cellspacing="0" cellpadding="0" id="Updates">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><xsl:value-of select="$locale/string[@name='S_Update_ComponentHead']"/></th>
|
||||
<th><xsl:value-of select="$locale/string[@name='S_Update_OldVersionHead']"/></th>
|
||||
<th><xsl:value-of select="$locale/string[@name='S_Update_SizeHead']"/></th>
|
||||
</tr>
|
||||
<xsl:apply-templates select="/Keyman/Updates/Update" />
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="update_controls">
|
||||
<xsl:call-template name="button">
|
||||
<xsl:with-param name="caption"><xsl:value-of select="$locale/string[@name='S_Button_Update_ApplyNow']"/></xsl:with-param>
|
||||
<xsl:with-param name="command">keyman:update_applynow</xsl:with-param>
|
||||
<xsl:with-param name="width">220px</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
|
||||
<xsl:call-template name="button">
|
||||
<xsl:with-param name="caption"><xsl:value-of select="$locale/string[@name='S_Button_Update_CheckNow']"/></xsl:with-param>
|
||||
<xsl:with-param name="command">keyman:update_checknow</xsl:with-param>
|
||||
<xsl:with-param name="width">220px</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</div>
|
||||
|
||||
<!-- <li><a href="keyman:support_updatecheck"><xsl:value-of select="$locale/string[@name='S_Button_CheckForUpdates']"/></a></li> -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="/Keyman/Updates/Update">
|
||||
<tr>
|
||||
<td class="UpdateCheckBox">
|
||||
<input type="checkbox">
|
||||
<xsl:attribute name="onclick">javascript:updateTick("<xsl:value-of select="index" />");</xsl:attribute>
|
||||
<xsl:attribute name="id">Update_<xsl:value-of select="index" /></xsl:attribute>
|
||||
<xsl:if test="not(@DefaultUnchecked)"><xsl:attribute name="checked">checked</xsl:attribute></xsl:if>
|
||||
<xsl:attribute name="name">Update_<xsl:value-of select="index" /></xsl:attribute>
|
||||
</input>
|
||||
<xsl:if test="RequiresAdmin">
|
||||
<span><xsl:attribute name="id">Update_<xsl:value-of select="index" />_RequiresAdmin</xsl:attribute></span>
|
||||
</xsl:if>
|
||||
</td>
|
||||
<xsl:choose>
|
||||
<xsl:when test="Package/Text != ''">
|
||||
<td class='component'>
|
||||
<label>
|
||||
<xsl:attribute name="for">Update_<xsl:value-of select="index"/></xsl:attribute>
|
||||
<xsl:value-of select="Package/Text"/>
|
||||
</label>
|
||||
</td>
|
||||
<td>
|
||||
<xsl:value-of select="Package/OldVersion"/>
|
||||
</td>
|
||||
<td>
|
||||
<xsl:value-of select="Package/DownloadSize"/>
|
||||
</td>
|
||||
</xsl:when>
|
||||
<xsl:when test="Keyman/DownloadURL != ''">
|
||||
<td>
|
||||
<label>
|
||||
<xsl:attribute name="for">Update_<xsl:value-of select="index"/></xsl:attribute>
|
||||
<xsl:value-of select="Keyman/Text"/>
|
||||
</label>
|
||||
</td>
|
||||
<td>
|
||||
<xsl:value-of select="Keyman/OldVersion"/>
|
||||
</td>
|
||||
<td>
|
||||
<xsl:value-of select="Keyman/DownloadSize"/>
|
||||
</td>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<td>
|
||||
<div id="DownloadFrom">
|
||||
<xsl:value-of select="$locale/string[@name='S_Update_DownloadFrom']"/>
|
||||
</div>
|
||||
<div id="URL">
|
||||
<a href="keyman:openwebsite">
|
||||
<xsl:value-of select="/Keyman/DownloadURL"/>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<xsl:value-of select="Keyman/DownloadVersion"/>
|
||||
</td>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</tr>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
Loading…
Add table
Reference in a new issue