mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-04 06:37:41 +00:00
- remove expandidentifiers - remove messages.txt - remove desktop.pot - remove stock message ditor - stop using captions altogether for translation
514 lines
16 KiB
ObjectPascal
514 lines
16 KiB
ObjectPascal
(*
|
|
Name: keymancustomisation
|
|
Copyright: Copyright (C) SIL International.
|
|
Documentation:
|
|
Description:
|
|
Create Date: 20 Jun 2006
|
|
|
|
Modified Date: 25 Oct 2016
|
|
Authors: mcdurdin
|
|
Related Files:
|
|
Dependencies:
|
|
|
|
Bugs:
|
|
Todo:
|
|
Notes:
|
|
History: 20 Jun 2006 - mcdurdin - Initial version
|
|
01 Aug 2006 - mcdurdin - Add MouseButton for menu items
|
|
14 Sep 2006 - mcdurdin - Add Welcome size, splash file name, supports character map properties
|
|
04 Dec 2006 - mcdurdin - Localization support
|
|
12 Dec 2006 - mcdurdin - Add DialogParameters and LanguageCode support
|
|
19 Mar 2007 - mcdurdin - I701 - Fix leaked com objects
|
|
23 Aug 2007 - mcdurdin - I933 - support locale in package
|
|
12 Oct 2007 - mcdurdin - I1093, I1039 - Handle errors around registry keys
|
|
27 Mar 2008 - mcdurdin - I1248 - Add TutorialCommandLine
|
|
26 Mar 2009 - mcdurdin - I1907 - Work around Developer installs
|
|
12 Mar 2010 - mcdurdin - I2230 - Resolve crashes due to incorrect reference counting
|
|
26 Jul 2010 - mcdurdin - I2467 - 8.0 renumber
|
|
26 Jul 2010 - mcdurdin - I2468 - Eliminate KeymanWeb Pack
|
|
22 Oct 2010 - mcdurdin - I2521 - Activation Client support for Developer 8.0
|
|
18 May 2012 - mcdurdin - I3306 - V9.0 - Remove TntControls + Win9x support
|
|
26 Jun 2012 - mcdurdin - I3383 - KM9 - ErrorControlledRegistry is obsolete
|
|
17 Aug 2012 - mcdurdin - I3377 - KM9 - Update code references from 8.0 to 9.0
|
|
19 Oct 2012 - mcdurdin - I3477 - V9.0 - Remove generic locale path function and use GetLocalPathForLocale
|
|
03 Jul 2014 - mcdurdin - I4314 - V9.0 - Icon size in tool tray is wrong when using large fonts
|
|
12 Aug 2014 - mcdurdin - I4314 - V9.0 - Icon size in tool tray is wrong when using large fonts
|
|
25 Oct 2016 - mcdurdin - I5122 - CrashID:kmshell.exe_10.0.751.0_2C684B25_EOleException
|
|
*)
|
|
unit keymancustomisation; // I3306
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Classes, SysUtils, ActiveX, ComObj,
|
|
Vcl.Graphics,
|
|
keymanapi_TLB,
|
|
KeymanAutoObject, KeymanContext,
|
|
internalinterfaces,
|
|
CustomisationStorage, CustomisationMessages,
|
|
CustomisationMenu,
|
|
custinterfaces;
|
|
|
|
type
|
|
ECustomisation = class(Exception)
|
|
end;
|
|
|
|
TCustomisationAutoObject = class;
|
|
|
|
ICustomisationInterface = interface
|
|
['{45B66C8D-A2AF-445A-96FD-34EDA8302D13}']
|
|
procedure DoDetach;
|
|
end;
|
|
|
|
TCustomisationInterfacedObject = class(TInterfacedObject, ICustomisationInterface)
|
|
protected
|
|
FCust: TCustomisationAutoObject;
|
|
|
|
function DoSerialize(Flags: TOleEnum; const ImagePath: WideString; References: TStrings): WideString;
|
|
function Serialize(Flags: TOleEnum; const ImagePath: WideString; References: TStrings): WideString;
|
|
function XMLClassName: WideString;
|
|
|
|
procedure DoDetach; virtual;
|
|
public
|
|
constructor Create(ACust: TCustomisationAutoObject); //; intf: TGUID);
|
|
destructor Destroy; override;
|
|
function SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HResult; override;
|
|
end;
|
|
|
|
TCustomisationMessages = class(TCustomisationInterfacedObject, IKeymanCustomisationMessages)
|
|
protected
|
|
function MessageFromID(const ID: WideString): WideString; overload; safecall;
|
|
function MessageFromID(const ID, LanguageCode: WideString): WideString; overload; safecall;
|
|
function GetAvailableLanguages: WideString; safecall;
|
|
function GetLanguageCode: WideString; safecall;
|
|
procedure SetLanguageCode(const Value: WideString); safecall;
|
|
function GetLocalePath: WideString; safecall;
|
|
procedure GetDialogParameters(const DialogName: WideString;
|
|
var FWidth: Integer; var FHeight: Integer); stdcall;
|
|
function GetLocalePathForLocale(const Locale: WideString): WideString; safecall;
|
|
procedure Load; safecall;
|
|
procedure Refresh; safecall;
|
|
end;
|
|
|
|
TCustomisationMenuItem = class(TCustomisationInterfacedObject, IIntKeymanInterface, IKeymanCustomisationMenuItem)
|
|
private
|
|
FIndex: Integer;
|
|
FMenuItem: CustomisationMenu.TCustomisationMenuItem;
|
|
protected
|
|
function Get_Location: TOleEnum; safecall;
|
|
function Get_ItemType: TCustomisationMenuItemType; safecall;
|
|
function Get_Caption: WideString; safecall;
|
|
function Get_Action: TCustomisationMenuItemAction; safecall;
|
|
function Get_CmdLine: WideString; safecall;
|
|
function Get_Icon: IPictureDisp; safecall;
|
|
function Get_PictureDefault: IPictureDisp; safecall;
|
|
function Get_PictureSelected: IPictureDisp; safecall;
|
|
function Get_Hotkey: Word; safecall;
|
|
function Get_Font: IFontDisp; safecall;
|
|
|
|
function Get_Index: Integer; safecall;
|
|
|
|
procedure DoDetach; override;
|
|
public
|
|
constructor Create(AIndex: Integer; ACust: TCustomisationAutoObject; AMenuItem: CustomisationMenu.TCustomisationMenuItem);
|
|
end;
|
|
|
|
TCustomisationMenuItems = class(TCustomisationInterfacedObject, IKeymanCustomisationMenuItems)
|
|
private
|
|
FItems: TAutoObjectList;
|
|
protected
|
|
function Get_Item(const Index: Integer): IKeymanCustomisationMenuItem; safecall;
|
|
function Get_Count: Integer; safecall;
|
|
procedure DoDetach; override;
|
|
public
|
|
constructor Create(ACust: TCustomisationAutoObject);
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
TCustomisationAutoObject = class(TKeymanAutoObject, IKeymanCustomisation, IKeymanUserInterface)
|
|
private
|
|
FFileName: string;
|
|
FStorage: TCustomisationStorage;
|
|
FMessages: TCustomisationMessageManager;
|
|
FMenu: TCustomisationMenu;
|
|
|
|
FCustMessages: IKeymanCustomisationMessages;
|
|
FCustMenuItems: IKeymanCustomisationMenuItems;
|
|
|
|
procedure LoadStorage;
|
|
protected
|
|
function Get_CustMenuItems: IKeymanCustomisationMenuItems; safecall;
|
|
function Get_CustMessages: IKeymanCustomisationMessages; safecall;
|
|
function Get_CustFile(const FileName: WideString): IStream; safecall;
|
|
procedure Refresh; safecall;
|
|
|
|
property CustMessages: IKeymanCustomisationMessages read Get_CustMessages;
|
|
property CustMenuItems: IKeymanCustomisationMenuItems read Get_CustMenuItems;
|
|
property CustFile[const FileName: WideString]: IStream read Get_CustFile;
|
|
public
|
|
constructor Create(AContext: TKeymanContext; const dispintf: TGUID; const AFileName: string);
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
onlineconstants,
|
|
utilhandleexception,
|
|
utilicon,
|
|
utilolepicture,
|
|
Vcl.Imaging.jpeg,
|
|
ErrorControlledRegistry,
|
|
RegistryKeys;
|
|
|
|
{ TCustomisationAutoObject }
|
|
|
|
constructor TCustomisationAutoObject.Create(AContext: TKeymanContext; const dispintf: TGUID; const AFileName: string);
|
|
begin
|
|
inherited Create(AContext, dispintf);
|
|
FFileName := AFileName;
|
|
FCustMessages := TCustomisationMessages.Create(Self);
|
|
FCustMenuItems := TCustomisationMenuItems.Create(Self);
|
|
LoadStorage;
|
|
FCustMessages.Load;
|
|
end;
|
|
|
|
destructor TCustomisationAutoObject.Destroy;
|
|
begin
|
|
(FCustMessages as ICustomisationInterface).DoDetach;
|
|
(FCustMenuItems as ICustomisationInterface).DoDetach;
|
|
|
|
FCustMessages := nil;
|
|
FCustMenuItems := nil;
|
|
|
|
FreeAndNil(FMessages);
|
|
FreeAndNil(FStorage);
|
|
FreeAndNil(FMenu);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TCustomisationAutoObject.Get_CustMessages: IKeymanCustomisationMessages;
|
|
begin
|
|
LoadStorage;
|
|
Result := FCustMessages;
|
|
end;
|
|
|
|
procedure TCustomisationAutoObject.LoadStorage;
|
|
begin
|
|
if Assigned(FStorage) then Exit;
|
|
// I5122
|
|
|
|
FStorage := TCustomisationStorage.Create(FFileName, nil, True);
|
|
FMessages := TCustomisationMessageManager.Create(FStorage.FileName);
|
|
FMenu := TCustomisationMenu.Create(FStorage);
|
|
end;
|
|
|
|
procedure TCustomisationAutoObject.Refresh;
|
|
begin
|
|
if Assigned(FCustMessages) then
|
|
FCustMessages.Refresh;
|
|
end;
|
|
|
|
function TCustomisationAutoObject.Get_CustFile(const FileName: WideString): IStream;
|
|
var
|
|
n: Integer;
|
|
begin
|
|
Result := nil;
|
|
with FStorage.CustFiles do
|
|
begin
|
|
n := IndexOfFileName(FileName);
|
|
if n < 0 then Exit;
|
|
Result := TStreamAdapter.Create(Items[n].Stream, soReference) as IStream;
|
|
end;
|
|
end;
|
|
|
|
function TCustomisationAutoObject.Get_CustMenuItems: IKeymanCustomisationMenuItems;
|
|
begin
|
|
LoadStorage;
|
|
Result := FCustMenuItems;
|
|
end;
|
|
|
|
{ TCustomisationMessages }
|
|
|
|
function TCustomisationMessages.GetAvailableLanguages: WideString;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FCust.FMessages)
|
|
then Result := FCust.FMessages.AvailableLanguages
|
|
else Result := '';
|
|
end;
|
|
|
|
procedure TCustomisationMessages.GetDialogParameters(
|
|
const DialogName: WideString; var FWidth, FHeight: Integer);
|
|
begin
|
|
if Assigned(FCust) then
|
|
FCust.FMessages.GetDialogParameters(DialogName, FWidth, FHeight);
|
|
end;
|
|
|
|
function TCustomisationMessages.GetLanguageCode: WideString;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FCust.FMessages)
|
|
then Result := FCust.FMessages.LanguageCode
|
|
else Result := '';
|
|
end;
|
|
|
|
function TCustomisationMessages.GetLocalePath: WideString;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FCust.FMessages)
|
|
then Result := FCust.FMessages.GetLocalePathForLocale('') // I3477
|
|
else Result := '';
|
|
end;
|
|
|
|
function TCustomisationMessages.GetLocalePathForLocale(
|
|
const Locale: WideString): WideString;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FCust.FMessages)
|
|
then Result := FCust.FMessages.GetLocalePathForLocale(Locale)
|
|
else Result := '';
|
|
end;
|
|
|
|
procedure TCustomisationMessages.Load;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FCust.FMessages) then
|
|
with TRegistryErrorControlled.Create do
|
|
try
|
|
if OpenKeyReadOnly(SRegKey_KeymanEngine_CU) and ValueExists(SRegValue_CurrentLanguage)
|
|
then FCust.FMessages.LanguageCode := ReadString(SRegValue_CurrentLanguage)
|
|
else FCust.FMessages.LanguageCode := '';
|
|
finally
|
|
Free;
|
|
end;
|
|
end;
|
|
|
|
function TCustomisationMessages.MessageFromID(const ID,
|
|
LanguageCode: WideString): WideString;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FCust.FMessages)
|
|
then Result := FCust.FMessages.MessageFromID(ID, LanguageCode)
|
|
else Result := '';
|
|
end;
|
|
|
|
procedure TCustomisationMessages.Refresh;
|
|
begin
|
|
Load;
|
|
end;
|
|
|
|
function TCustomisationMessages.MessageFromID(const ID: WideString): WideString;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FCust.FMessages)
|
|
then Result := FCust.FMessages.MessageFromID(ID)
|
|
else Result := '';
|
|
end;
|
|
|
|
procedure TCustomisationMessages.SetLanguageCode(const Value: WideString);
|
|
begin
|
|
if Assigned(FCust) then
|
|
begin
|
|
if Assigned(FCust.FMessages) then
|
|
FCust.FMessages.LanguageCode := Value;
|
|
|
|
with TRegistryErrorControlled.Create do // I1093, I1039 - 'Failed to set data for current language'
|
|
try
|
|
if not OpenKey(SRegKey_KeymanEngine_CU, True) then
|
|
RaiseLastOSError(Integer(LastError)); // I1093, I1039 - 'Failed to set data for current language'
|
|
WriteString(SRegValue_CurrentLanguage, string(Value));
|
|
finally
|
|
Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TCustomisationInterfacedObject }
|
|
|
|
constructor TCustomisationInterfacedObject.Create(ACust: TCustomisationAutoObject); //; intf: TGUID);
|
|
begin
|
|
inherited Create;
|
|
FCust := ACust;
|
|
end;
|
|
|
|
destructor TCustomisationInterfacedObject.Destroy;
|
|
begin
|
|
DoDetach;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TCustomisationInterfacedObject.DoDetach;
|
|
begin
|
|
FCust := nil;
|
|
end;
|
|
|
|
function TCustomisationInterfacedObject.DoSerialize(Flags: TOleEnum;
|
|
const ImagePath: WideString; References: TStrings): WideString;
|
|
begin
|
|
Result := '';
|
|
end;
|
|
|
|
function TCustomisationInterfacedObject.SafeCallException(
|
|
ExceptObject: TObject; ExceptAddr: Pointer): HResult;
|
|
begin
|
|
if (ExceptObject is Exception) and not (ExceptObject is EOleException) { for some reason, we lose the class name EKeyman? } then
|
|
LogException(ClassName, ExceptObject as Exception, ExceptAddr);
|
|
Result := HandleSafeCallException(ExceptObject, ExceptAddr, IKeyman, '', '');
|
|
|
|
end;
|
|
|
|
function TCustomisationInterfacedObject.Serialize(Flags: TOleEnum;
|
|
const ImagePath: WideString; References: TStrings): WideString;
|
|
begin
|
|
Result := '';
|
|
end;
|
|
|
|
function TCustomisationInterfacedObject.XMLClassName: WideString;
|
|
begin
|
|
Result := '';
|
|
end;
|
|
|
|
{ TCustomisationMenuItem }
|
|
|
|
constructor TCustomisationMenuItem.Create(AIndex: Integer; ACust: TCustomisationAutoObject; AMenuItem: CustomisationMenu.TCustomisationMenuItem);
|
|
begin
|
|
inherited Create(ACust); // (ACust, IKeymanCustomisationMenuItem);
|
|
FIndex := AIndex;
|
|
FMenuItem := AMenuItem;
|
|
end;
|
|
|
|
procedure TCustomisationMenuItem.DoDetach;
|
|
begin
|
|
inherited;
|
|
FMenuItem := nil;
|
|
end;
|
|
|
|
function TCustomisationMenuItem.Get_Action: TCustomisationMenuItemAction;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FMenuItem)
|
|
then Result := FMenuItem.Action
|
|
else Result := miaNull;
|
|
end;
|
|
|
|
function TCustomisationMenuItem.Get_Caption: WideString;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FMenuItem)
|
|
then Result := FMenuItem.Caption
|
|
else Result := '';
|
|
end;
|
|
|
|
function TCustomisationMenuItem.Get_CmdLine: WideString;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FMenuItem)
|
|
then Result := FMenuItem.CmdLine
|
|
else Result := '';
|
|
end;
|
|
|
|
function TCustomisationMenuItem.Get_Font: IFontDisp;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FMenuItem)
|
|
then GetOleFont(FMenuItem.Font, Result)
|
|
else Result := nil;
|
|
end;
|
|
|
|
function TCustomisationMenuItem.Get_Hotkey: Word;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FMenuItem)
|
|
then Result := FMenuItem.Hotkey
|
|
else Result := 0;
|
|
end;
|
|
|
|
function TCustomisationMenuItem.Get_Icon: IPictureDisp;
|
|
begin
|
|
if not Assigned(FCust) or not Assigned(FMenuItem) or not Assigned(FMenuItem.Icon.Graphic) then
|
|
Result := nil
|
|
else
|
|
begin
|
|
GetOlePictureEx(FMenuItem.Icon, Result);
|
|
end;
|
|
end;
|
|
|
|
function TCustomisationMenuItem.Get_Index: Integer;
|
|
begin
|
|
Result := FIndex;
|
|
end;
|
|
|
|
function TCustomisationMenuItem.Get_ItemType: TCustomisationMenuItemType;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FMenuItem)
|
|
then Result := FMenuItem.ItemType
|
|
else Result := mitText;
|
|
end;
|
|
|
|
function TCustomisationMenuItem.Get_Location: TOleEnum;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FMenuItem)
|
|
then Result := FMenuItem.Location
|
|
else Result := milLeft;
|
|
end;
|
|
|
|
function TCustomisationMenuItem.Get_PictureDefault: IPictureDisp;
|
|
begin
|
|
if not Assigned(FCust) or not Assigned(FMenuItem) or not Assigned(FMenuItem.PictureDefault.Graphic) then
|
|
Result := nil
|
|
else
|
|
begin
|
|
GetOlePictureEx(FMenuItem.PictureDefault, Result);
|
|
end;
|
|
end;
|
|
|
|
function TCustomisationMenuItem.Get_PictureSelected: IPictureDisp;
|
|
begin
|
|
if not Assigned(FCust) or not Assigned(FMenuItem) or not Assigned(FMenuItem.PictureSelected.Graphic) then
|
|
Result := nil
|
|
else
|
|
begin
|
|
GetOlePictureEx(FMenuItem.PictureSelected, Result);
|
|
end;
|
|
end;
|
|
|
|
{ TCustomisationMenuItems }
|
|
|
|
constructor TCustomisationMenuItems.Create(ACust: TCustomisationAutoObject);
|
|
begin
|
|
inherited Create(ACust);
|
|
FItems := TAutoObjectList.Create;
|
|
end;
|
|
|
|
destructor TCustomisationMenuItems.Destroy;
|
|
begin
|
|
inherited;
|
|
FreeAndNil(FItems);
|
|
end;
|
|
|
|
procedure TCustomisationMenuItems.DoDetach;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
inherited;
|
|
for i := 0 to FItems.Count - 1 do
|
|
(FItems[i] as ICustomisationInterface).DoDetach;
|
|
end;
|
|
|
|
function TCustomisationMenuItems.Get_Count: Integer;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FCust.FMenu)
|
|
then Result := FCust.FMenu.Items.Count
|
|
else Result := 0;
|
|
end;
|
|
|
|
function TCustomisationMenuItems.Get_Item(
|
|
const Index: Integer): IKeymanCustomisationMenuItem;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if Assigned(FCust) and Assigned(FCust.FMenu) then
|
|
begin
|
|
for i := 0 to FItems.Count - 1 do
|
|
if (FItems[i] as IKeymanCustomisationMenuItem).Index = Index then
|
|
begin
|
|
Result := FItems[i] as IKeymanCustomisationMenuItem;
|
|
Exit;
|
|
end;
|
|
Result := TCustomisationMenuItem.Create(Index, FCust, FCust.FMenu.Items[Index-1]);
|
|
FItems.Add(Result as IIntKeymanInterface);
|
|
end
|
|
else Result := nil;
|
|
end;
|
|
|
|
end.
|
|
|