spiegel-keyman/windows/src/engine/kmcomapi/com/customisation/keymancustomisation.pas
Marc Durdin 6b748239ed chore(windows): cleanup of i18n
- remove expandidentifiers
- remove messages.txt
- remove desktop.pot
- remove stock message ditor
- stop using captions altogether for translation
2020-07-27 16:54:23 +10:00

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.