diff --git a/common/windows/delphi/general/RegistryKeys.pas b/common/windows/delphi/general/RegistryKeys.pas index 91a9af51448..5cc6556aa67 100644 --- a/common/windows/delphi/general/RegistryKeys.pas +++ b/common/windows/delphi/general/RegistryKeys.pas @@ -374,6 +374,7 @@ interface SRegValue_IDEOptDebuggerAutoResetBeforeCompiling = 'debugger auto reset before compilng'; // CU SRegValue_IDEOptAutoSaveBeforeCompiling = 'auto save before compiling'; // CU SRegValue_IDEOptOSKAutoSaveBeforeImporting = 'osk auto save before importing'; // CU + SRegValue_IDEOptPromptToUpgradeProjects = 'prompt to upgrade projects'; // CU // Note: keeping 'web host port' reg value name to ensure settings maintained // from version 14.0 and earlier of Keyman Developer. Other values are diff --git a/developer/src/kmconvert/kmconvert.dpr b/developer/src/kmconvert/kmconvert.dpr index be9aeae418e..70e34e13c3f 100644 --- a/developer/src/kmconvert/kmconvert.dpr +++ b/developer/src/kmconvert/kmconvert.dpr @@ -85,7 +85,9 @@ uses KeymanPaths in '..\..\..\common\windows\delphi\general\KeymanPaths.pas', Keyman.System.Standards.LangTagsRegistry in '..\..\..\common\windows\delphi\standards\Keyman.System.Standards.LangTagsRegistry.pas', Keyman.Developer.System.Project.UrlRenderer in '..\TIKE\project\Keyman.Developer.System.Project.UrlRenderer.pas', - Keyman.System.LexicalModelUtils in '..\common\delphi\lexicalmodels\Keyman.System.LexicalModelUtils.pas'; + Keyman.System.LexicalModelUtils in '..\common\delphi\lexicalmodels\Keyman.System.LexicalModelUtils.pas', + KeymanDeveloperOptions in '..\tike\main\KeymanDeveloperOptions.pas', + Keyman.Developer.System.KeymanDeveloperPaths in '..\tike\main\Keyman.Developer.System.KeymanDeveloperPaths.pas'; {$R icons.RES} {$R version.res} diff --git a/developer/src/kmconvert/kmconvert.dproj b/developer/src/kmconvert/kmconvert.dproj index cb90099eff2..29b9aa366f4 100644 --- a/developer/src/kmconvert/kmconvert.dproj +++ b/developer/src/kmconvert/kmconvert.dproj @@ -194,6 +194,8 @@ + + Cfg_2 Base diff --git a/developer/src/tike/actions/dmActionsMain.pas b/developer/src/tike/actions/dmActionsMain.pas index eff73c4d8ec..9594ce5c6ff 100644 --- a/developer/src/tike/actions/dmActionsMain.pas +++ b/developer/src/tike/actions/dmActionsMain.pas @@ -637,7 +637,11 @@ procedure TmodActionsMain.actProjectSettingsExecute(Sender: TObject); then frm := TfrmProjectSettings.Create(Screen.ActiveForm) // I4688 else frm := TfrmProjectSettings20.Create(Screen.ActiveForm); try - frm.ShowModal; + if frm.ShowModal = mrOk then + begin + if IsGlobalProjectUIReady then + FGlobalProject.Refresh; + end; finally frm.Free; end; diff --git a/developer/src/tike/dialogs/UfrmOptions.dfm b/developer/src/tike/dialogs/UfrmOptions.dfm index 3bff861879e..426f2d3bc41 100644 --- a/developer/src/tike/dialogs/UfrmOptions.dfm +++ b/developer/src/tike/dialogs/UfrmOptions.dfm @@ -29,7 +29,7 @@ inherited frmOptions: TfrmOptions Top = 185 Width = 125 Height = 25 - Caption = '&Proxy Settings...' + Caption = 'Prox&y Settings...' TabOrder = 4 OnClick = cmdProxySettingsClick end @@ -38,7 +38,7 @@ inherited frmOptions: TfrmOptions Top = 47 Width = 401 Height = 45 - Caption = '&External Editor Path' + Caption = 'E&xternal Editor Path' TabOrder = 1 object editExternalEditorPath: TEdit Left = 8 @@ -61,7 +61,7 @@ inherited frmOptions: TfrmOptions Top = 216 Width = 125 Height = 25 - Caption = 'S&MTP Settings...' + Caption = '&SMTP Settings...' TabOrder = 5 OnClick = cmdSMTPSettingsClick end @@ -101,7 +101,7 @@ inherited frmOptions: TfrmOptions Top = 16 Width = 69 Height = 21 - Caption = '&Browse...' + Caption = 'Bro&wse...' TabOrder = 1 OnClick = cmdBrowseDefaultProjectPathClick end @@ -119,7 +119,7 @@ inherited frmOptions: TfrmOptions Top = 181 Width = 218 Height = 17 - Caption = '&Automatically save before importing OSK' + Caption = 'Au&tomatically save before importing OSK' TabOrder = 7 end object gbPrivacy: TGroupBox @@ -128,13 +128,13 @@ inherited frmOptions: TfrmOptions Width = 401 Height = 73 Caption = 'Privacy' - TabOrder = 8 + TabOrder = 9 object chkReportUsage: TCheckBox Left = 8 Top = 44 Width = 311 Height = 17 - Caption = '&Share anonymous usage statistics with keyman.com' + Caption = 'Share anonymous &usage statistics with keyman.com' TabOrder = 1 end object chkReportErrors: TCheckBox @@ -146,6 +146,14 @@ inherited frmOptions: TfrmOptions TabOrder = 0 end end + object chkPromptToUpgradeProjects: TCheckBox + Left = 151 + Top = 204 + Width = 218 + Height = 17 + Caption = '&Prompt to upgrade projects to 17.0 format' + TabOrder = 8 + end end object tabEditor: TTabSheet Caption = 'Editor' diff --git a/developer/src/tike/dialogs/UfrmOptions.pas b/developer/src/tike/dialogs/UfrmOptions.pas index 683b6d5e8d2..2b4b5b48e6a 100644 --- a/developer/src/tike/dialogs/UfrmOptions.pas +++ b/developer/src/tike/dialogs/UfrmOptions.pas @@ -104,6 +104,7 @@ TfrmOptions = class(TTikeForm) gbServer: TGroupBox; chkListLocalURLs: TCheckBox; cmdConfigureServer: TButton; + chkPromptToUpgradeProjects: TCheckBox; procedure FormCreate(Sender: TObject); procedure cmdOKClick(Sender: TObject); procedure cmdDefaultFontClick(Sender: TObject); @@ -192,6 +193,7 @@ procedure TfrmOptions.FormCreate(Sender: TObject); chkDebuggerAutoResetBeforeCompiling.Checked := DebuggerAutoResetBeforeCompiling; chkAutoSaveBeforeCompiling.Checked := AutoSaveBeforeCompiling; chkOSKAutoSaveBeforeImporting.Checked := OSKAutoSaveBeforeImporting; + chkPromptToUpgradeProjects.Checked := PromptToUpgradeProjects; chkCharMapAutoLookup.Checked := CharMapAutoLookup; chkCharMapDisableDatabaseLookups.Checked := CharMapDisableDatabaseLookups; @@ -291,6 +293,7 @@ procedure TfrmOptions.cmdOKClick(Sender: TObject); DebuggerAutoResetBeforeCompiling := chkDebuggerAutoResetBeforeCompiling.Checked; AutoSaveBeforeCompiling := chkAutoSaveBeforeCompiling.Checked; OSKAutoSaveBeforeImporting := chkOSKAutoSaveBeforeImporting.Checked; + PromptToUpgradeProjects := chkPromptToUpgradeProjects.Checked; ServerUseLocalAddresses := chkListLocalURLs.Checked; diff --git a/developer/src/tike/main/KeymanDeveloperOptions.pas b/developer/src/tike/main/KeymanDeveloperOptions.pas index 4f757b17da4..5d2452fa4a0 100644 --- a/developer/src/tike/main/KeymanDeveloperOptions.pas +++ b/developer/src/tike/main/KeymanDeveloperOptions.pas @@ -69,6 +69,7 @@ TKeymanDeveloperOptions = class FServerNgrokToken: string; FServerNgrokRegion: string; FServerKeepAlive: Boolean; + FPromptToUpgradeProjects: Boolean; procedure CloseRegistry; procedure OpenRegistry; function regReadString(const nm, def: string): string; @@ -102,6 +103,7 @@ TKeymanDeveloperOptions = class property DebuggerAutoResetBeforeCompiling: Boolean read FDebuggerAutoResetBeforeCompiling write FDebuggerAutoResetBeforeCompiling; property AutoSaveBeforeCompiling: Boolean read FAutoSaveBeforeCompiling write FAutoSaveBeforeCompiling; property OSKAutoSaveBeforeImporting: Boolean read FOSKAutoSaveBeforeImporting write FOSKAutoSaveBeforeImporting; + property PromptToUpgradeProjects: Boolean read FPromptToUpgradeProjects write FPromptToUpgradeProjects; property ReportErrors: Boolean read FReportErrors write FReportErrors; property ReportUsage: Boolean read FReportUsage write FReportUsage; @@ -211,6 +213,7 @@ procedure TKeymanDeveloperOptions.Read; FDebuggerAutoResetBeforeCompiling := regReadBool(SRegValue_IDEOptDebuggerAutoResetBeforeCompiling, False); FAutoSaveBeforeCompiling := regReadBool(SRegValue_IDEOptAutoSaveBeforeCompiling, False); FOSKAutoSaveBeforeImporting := regReadBool(SRegValue_IDEOptOSKAutoSaveBeforeImporting, False); + FPromptToUpgradeProjects := regReadBool(SRegValue_IDEOptPromptToUpgradeProjects, True); FServerDefaultPort := regReadInt(SRegValue_IDEOptServerPort, 8008); FServerKeepAlive := regReadBool(SRegValue_IDEOptServerKeepAlive, False); @@ -270,6 +273,7 @@ procedure TKeymanDeveloperOptions.Write; regWriteBool(SRegValue_IDEOptDebuggerAutoResetBeforeCompiling, FDebuggerAutoResetBeforeCompiling); regWriteBool(SRegValue_IDEOptAutoSaveBeforeCompiling, FAutoSaveBeforeCompiling); regWriteBool(SRegValue_IDEOptOSKAutoSaveBeforeImporting, FOSKAutoSaveBeforeImporting); + regWriteBool(SRegValue_IDEOptPromptToUpgradeProjects, FPromptToUpgradeProjects); regWriteInt(SRegValue_IDEOptServerPort, FServerDefaultPort); regWriteBool(SRegValue_IDEOptServerKeepAlive, FServerKeepAlive); diff --git a/developer/src/tike/main/UfrmMain.pas b/developer/src/tike/main/UfrmMain.pas index 53fd7e378e7..c988dc1b743 100644 --- a/developer/src/tike/main/UfrmMain.pas +++ b/developer/src/tike/main/UfrmMain.pas @@ -1462,7 +1462,7 @@ procedure TfrmKeymanDeveloper.UpdateFileMRU; begin m := TMenuItem.Create(Self); m.Caption := '&'+IntToStr(i+1)+' '+FGlobalProject.MRU.EllipsisFile(i); - m.Hint := FGlobalProject.MRU.Files[i]; + m.Tag := i; m.OnClick := mnuFileRecentFileClick; mnuFileRecent.Add(m); end; @@ -1470,9 +1470,11 @@ procedure TfrmKeymanDeveloper.UpdateFileMRU; end; procedure TfrmKeymanDeveloper.mnuFileRecentFileClick(Sender: TObject); +var + filename: string; begin - with Sender as TMenuItem do - OpenFilesInProject([Hint]); + filename := FGlobalProject.MRU.Files[(Sender as TMenuItem).Tag]; + OpenFilesInProject([filename]); end; {------------------------------------------------------------------------------- @@ -1552,7 +1554,7 @@ procedure TfrmKeymanDeveloper.mnuProjectClick(Sender: TObject); begin m := TMenuItem.Create(Self); m.Caption := '&'+IntToStr(i+1)+' '+FProjectMRU.EllipsisFile(i); - m.Hint := FProjectMRU.Files[i]; + m.Tag := i; m.OnClick := mnuProjectRecentFileClick; mnuProjectsRecent.Add(m); end; @@ -1567,7 +1569,7 @@ procedure TfrmKeymanDeveloper.mnuProjectRecentFileClick(Sender: TObject); var filename: string; begin - filename := (Sender as TMenuItem).Hint; + filename := FProjectMRU.Files[(Sender as TMenuItem).Tag]; OpenProject(filename); end; diff --git a/developer/src/tike/main/mrulist.pas b/developer/src/tike/main/mrulist.pas index ad207471eff..d2e88e94cac 100644 --- a/developer/src/tike/main/mrulist.pas +++ b/developer/src/tike/main/mrulist.pas @@ -231,11 +231,13 @@ destructor TMRUList.Destroy; end; function TMRUList.EllipsisFile(Index: Integer): string; +var + buffer: array[0..MAX_PATH] of char; begin - Result := Files[Index]; + StrPCopy(buffer, Files[Index]); - if PathCompactPath(0, PWideChar(Result), GetSystemMetrics(SM_CXSCREEN) div 3) then // I4697 - Result := string(PChar(Result)) // This removes the terminating nul + if PathCompactPath(0, buffer, GetSystemMetrics(SM_CXSCREEN) div 3) then // I4697 + Result := buffer // This removes the terminating nul else Result := ExtractFileName(Files[Index]); end; diff --git a/developer/src/tike/project/Keyman.Developer.System.Project.ProjectFile.pas b/developer/src/tike/project/Keyman.Developer.System.Project.ProjectFile.pas index 4e2fad5ec6c..0893a9ae8a6 100644 --- a/developer/src/tike/project/Keyman.Developer.System.Project.ProjectFile.pas +++ b/developer/src/tike/project/Keyman.Developer.System.Project.ProjectFile.pas @@ -922,6 +922,7 @@ function TProject.Render: WideString; // TProjectUrlRenderer.AddUrls(doc.documentElement); + TProjectUrlRenderer.AddProcessState(doc.documentElement); xsl := MSXMLDOMDocumentFactory.CreateDOMDocument; try diff --git a/developer/src/tike/project/Keyman.Developer.System.Project.ProjectFiles.pas b/developer/src/tike/project/Keyman.Developer.System.Project.ProjectFiles.pas index 112fcee68f7..adf7bbd1f59 100644 --- a/developer/src/tike/project/Keyman.Developer.System.Project.ProjectFiles.pas +++ b/developer/src/tike/project/Keyman.Developer.System.Project.ProjectFiles.pas @@ -72,5 +72,7 @@ initialization RegisterProjectFileType('.js', TOpenableProjectFile); RegisterProjectFileType('.kpj', TOpenableProjectFile); RegisterProjectFileType('.user', TOpenableProjectFile); + RegisterProjectFileType('.keyman-touch-layout', TOpenableProjectFile); + RegisterProjectFileType('.keyboard_info', TOpenableProjectFile); end. diff --git a/developer/src/tike/project/Keyman.Developer.System.Project.UrlRenderer.pas b/developer/src/tike/project/Keyman.Developer.System.Project.UrlRenderer.pas index 32230c66561..da6e970050c 100644 --- a/developer/src/tike/project/Keyman.Developer.System.Project.UrlRenderer.pas +++ b/developer/src/tike/project/Keyman.Developer.System.Project.UrlRenderer.pas @@ -8,15 +8,26 @@ interface type TProjectUrlRenderer = class class procedure AddUrls(root: IXMLDomNode); + class procedure AddProcessState(root: IXMLDomNode); end; implementation uses + KeymanDeveloperOptions, Upload_Settings; { TProjectUrlRenderer } +class procedure TProjectUrlRenderer.AddProcessState(root: IXMLDomNode); +var + node: IXMLDomElement; +begin + node := root.ownerDocument.createElement('DeveloperState'); + node.setAttribute('promptToUpgradeProjects', FKeymanDeveloperOptions.PromptToUpgradeProjects); + root.appendChild(node); +end; + class procedure TProjectUrlRenderer.AddUrls(root: IXMLDomNode); var node: IXMLDomNode; diff --git a/developer/src/tike/project/Keyman.Developer.UI.Project.UfrmProject.pas b/developer/src/tike/project/Keyman.Developer.UI.Project.UfrmProject.pas index e1c5a73621e..1fc991143cf 100644 --- a/developer/src/tike/project/Keyman.Developer.UI.Project.UfrmProject.pas +++ b/developer/src/tike/project/Keyman.Developer.UI.Project.UfrmProject.pas @@ -94,6 +94,7 @@ TfrmProject = class(TfrmTikeChild) // I2721 procedure SetGlobalProject; procedure StartClose; override; procedure CompileAll; + procedure RefreshOptions; override; end; implementation @@ -202,6 +203,12 @@ procedure TfrmProject.RefreshHTML; RefreshCaption; end; +procedure TfrmProject.RefreshOptions; +begin + inherited; + ProjectRefresh(nil); +end; + procedure TfrmProject.ProjectRefresh(Sender: TObject); begin if frmKeymanDeveloper.ActiveChild <> Self diff --git a/developer/src/tike/project/Keyman.Developer.UI.Project.UfrmProjectSettings20.pas b/developer/src/tike/project/Keyman.Developer.UI.Project.UfrmProjectSettings20.pas index 78c945a6935..e963c32781c 100644 --- a/developer/src/tike/project/Keyman.Developer.UI.Project.UfrmProjectSettings20.pas +++ b/developer/src/tike/project/Keyman.Developer.UI.Project.UfrmProjectSettings20.pas @@ -58,7 +58,23 @@ implementation utildir; procedure TfrmProjectSettings20.cmdOKClick(Sender: TObject); +var + path: string; begin + path := Trim(DosSlashes(editOutputPath.Text)); + if (path <> '') and (not path.StartsWith('$PROJECTPATH') or (path.CountChar('\') > 1)) then + begin + ShowMessage('Output path "'+path+'" should start with "$PROJECTPATH" and be no more than one level deep.'); + Exit; + end; + + path := Trim(DosSlashes(editSourcePath.Text)); + if (path <> '') and (not path.StartsWith('$PROJECTPATH') or (path.CountChar('\') > 1)) then + begin + ShowMessage('Source path "'+path+'" should start with "$PROJECTPATH" and be no more than one level deep.'); + Exit; + end; + FGlobalProject.Options.BuildPath := Trim(DosSlashes(editOutputPath.Text)); FGlobalProject.Options.SourcePath := Trim(DosSlashes(editSourcePath.Text)); FGlobalProject.Options.SkipMetadataFiles := not chkBuildMetadataFiles.Checked; diff --git a/developer/src/tike/project/Keyman.Developer.UI.Project.xmlLdmlProjectFileUI.pas b/developer/src/tike/project/Keyman.Developer.UI.Project.xmlLdmlProjectFileUI.pas index e4abe152010..56430534f36 100644 --- a/developer/src/tike/project/Keyman.Developer.UI.Project.xmlLdmlProjectFileUI.pas +++ b/developer/src/tike/project/Keyman.Developer.UI.Project.xmlLdmlProjectFileUI.pas @@ -135,85 +135,8 @@ procedure TxmlLdmlProjectFileUI.SetDebug(const Value: Boolean); end; function TxmlLdmlProjectFileUI.TestKeymanWeb(FSilent: Boolean): Boolean; // I4409 -(*var - FCompiledName: string; - editor: TfrmTikeEditor; - wizard: TfrmEditor; - i: TKeyboardFont; - j: TKeyboardFont; - Found: Boolean; - - function IsStandardFont(const FontName: string): Boolean; // I4448 - const - StandardFontNames: array[0..9] of string = ( - 'Arial', 'Calibri', 'Consolas', 'Courier New', 'Lucida Console', 'Lucida Sans Unicode', 'Segoe UI', 'Tahoma', 'Times New Roman', 'Verdana' - ); - begin - Result := AnsiIndexText(FontName, StandardFontNames) >= 0; - end; - - procedure RegisterFont(const fontname: string); - var - strm: TMemoryStream; - begin - if (fontname <> '') and not IsStandardFont(fontname) then - begin - strm := TMemoryStream.Create; - try - if TFontLoadUtil.LoadFontData(fontname, strm) and - TServerDebugAPI.Running then - TServerDebugAPI.RegisterFont(strm, fontname); - finally - strm.Free; - end; - end; - end; -begin - editor := frmKeymanDeveloper.FindEditorByFileName(ProjectFile.FileName); // I4021 - if not Assigned(editor) or not (editor is TfrmKeymanWizard) then - Exit(False); - wizard := editor as TfrmKeymanWizard; - - if ProjectFile.Targets * KMWKeymanTargets = [] then - Exit(False); - - FCompiledName := ProjectFile.JSTargetFilename; - if FCompiledName = '' then - Exit(False); - - if not TestKeyboardState(FCompiledName, FSilent) then - Exit(False); - - // We register all fonts that are used by the layout, - // but just once for each reference! - for i := kfontChar to kfontTouchLayoutDesktop do - begin - Found := False; - for j := kfontChar to TKeyboardFont(Ord(i)-1) do - if Wizard.FontInfo[j].Name = Wizard.FontInfo[i].Name then - begin - Found := True; - Break; - end; - if not Found then - RegisterFont(Wizard.FontInfo[i].Name); - end; - - if TServerUI.VerifyServerRunning then - begin - TServerDebugAPI.RegisterKeyboard( - FCompiledName, - ProjectFile.FileVersion, - // We only need to specify the char + osk fonts here - // as the others are referenced in the touch layout definition directly - Wizard.FontInfo[kfontChar].Name, - Wizard.FontInfo[kfontOSK].Name - ); - - wizard.NotifyStartedWebDebug; // I4021 - end; -*) begin + // TODO (18.0): when we have web support for ldml keyboards Result := True; end; diff --git a/developer/src/tike/xml/project/elements.xsl b/developer/src/tike/xml/project/elements.xsl index ba5a41fdee6..8265cd3e17e 100644 --- a/developer/src/tike/xml/project/elements.xsl +++ b/developer/src/tike/xml/project/elements.xsl @@ -278,7 +278,8 @@ - +

⚠️ This project file is in an old format. You should upgrade it to the Keyman Developer 17.0 project format.