diff --git a/client/DelphiLintClientProjects250.groupproj b/client/DelphiLintClientProjects250.groupproj new file mode 100644 index 00000000..57c1ebe1 --- /dev/null +++ b/client/DelphiLintClientProjects250.groupproj @@ -0,0 +1,48 @@ + + + {E13F5E64-5BEF-4919-9E81-0DFCBA69E1B4} + + + + + + + + + + + Default.Personality.12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/source/DelphiLint.Analyzer.pas b/client/source/DelphiLint.Analyzer.pas index 2c94d3fc..e2361302 100644 --- a/client/source/DelphiLint.Analyzer.pas +++ b/client/source/DelphiLint.Analyzer.pas @@ -158,7 +158,7 @@ procedure TAnalyzerImpl.AnalyzeFiles(const Files: TArray; const ProjectF end else if not LintContext.Settings.StandaloneUseDefaultRules then begin AnalyzeOptions.UseDefaultRules := False; - AnalyzeOptions.DisabledRules := SplitString(LintContext.Settings.StandaloneDisabledRules, ','); + AnalyzeOptions.DisabledRules := TArray(SplitString(LintContext.Settings.StandaloneDisabledRules, ',')); end; DoAnalyzeFiles(AnalyzeOptions, ProjectOptions.SonarHostDownloadPlugin); diff --git a/client/source/DelphiLint.FileLogger.pas b/client/source/DelphiLint.FileLogger.pas index 54c443c9..26b4f512 100644 --- a/client/source/DelphiLint.FileLogger.pas +++ b/client/source/DelphiLint.FileLogger.pas @@ -66,7 +66,7 @@ constructor TFileLogger.Create(LogPath: string); FLock := TMutex.Create; if not TFile.Exists(FLogPath) then begin - FreeAndNil(TFile.Create(FLogPath)); + TFile.Create(FLogPath).Free; end; end; diff --git a/client/source/DelphiLint.Handlers.pas b/client/source/DelphiLint.Handlers.pas index 510df847..b70fcbac 100644 --- a/client/source/DelphiLint.Handlers.pas +++ b/client/source/DelphiLint.Handlers.pas @@ -319,7 +319,7 @@ destructor TEditorHandler.Destroy; // Although these hooks are owned by the context menu, we need to free them when the plugin is disabled for Hook in FPopupHooks.Values do begin Hook.OnFreed.RemoveListener(OnHookFreed); - FreeAndNil(Hook); + Hook.Free; end; FreeAndNil(FPopupHooks); diff --git a/client/source/DelphiLint.HtmlGen.pas b/client/source/DelphiLint.HtmlGen.pas index cf82caef..a3aa87bb 100644 --- a/client/source/DelphiLint.HtmlGen.pas +++ b/client/source/DelphiLint.HtmlGen.pas @@ -354,6 +354,59 @@ function TRuleHtmlGenerator.GenerateRuleDescriptionHtml(Description: TRuleDescri //______________________________________________________________________________________________________________________ function TRuleHtmlGenerator.BuildHtmlPage(BodyHtml: string; BodyClass: string): string; + + function GetLegacyScript: string; + begin + Result := + 'function hasClass(element, className) {' + + ' return element.className && element.className.indexOf(className) !== -1;' + + '}' + + 'function addClass(element, className) {' + + ' if (!hasClass(element, className)) { element.className += " " + className }' + + '}' + + 'function removeClass(element, className) {' + + ' if (!hasClass(element, className)) { return }' + + ' element.className = element.className.replace(" " + className, "").replace(className, "");' + + '}' + + 'function getElementsWithClass(className) {' + + ' var elements = [];' + + ' var allElements = document.getElementsByTagName("*");' + + ' for (var i = 0; i < allElements.length; i++) {' + + ' if (hasClass(allElements[i], className)) { elements.push(allElements[i]) }' + + ' }' + + ' return elements;' + + '}' + + 'function highlightTag(tagName) {' + + ' var preElements = document.getElementsByTagName(tagName);' + + ' for (var i = 0; i < preElements.length; i++) {' + + ' var pre = preElements[i];' + + ' if (pre.getAttribute("data-diff-type")) {' + + ' addClass(pre, "hljs");' + + ' }' + + ' }' + + '};' + + 'function registerTabs() {' + + ' var tabBtns = getElementsWithClass("tab-btn");' + + ' for (var i = 0; i < tabBtns.length; i++) {' + + ' tabBtns[i].onclick = function () {' + + ' var activeButtons = getElementsWithClass("tab-btn active");' + + ' var activeContents = getElementsWithClass("tab-content active");' + + ' for (var j = 0; j < activeButtons.length ; j++) { removeClass(activeButtons[j], "active") }' + + ' for (var k = 0; k < activeContents.length; k++) { removeClass(activeContents[k], "active") }' + + ' addClass(this, "active");' + + ' var targetId = this.getAttribute("data-content-id");' + + ' var targetContent = document.getElementById(targetId);' + + ' if (targetContent) { addClass(targetContent, "active") }' + + ' };' + + ' }' + + '};' + + 'function initLegacy() {' + + ' highlightTag("pre");' + + ' registerTabs();' + + '};' + + 'setTimeout(initLegacy, 100);'; + end; + begin Result := Format( '' + @@ -364,7 +417,15 @@ function TRuleHtmlGenerator.BuildHtmlPage(BodyHtml: string; BodyClass: string): '' + '' + '
%s
' + - ' ' + + ' ' + '' + '', [GenerateCss, BodyClass, BodyHtml]); diff --git a/client/source/DelphiLint.IDEContext.pas b/client/source/DelphiLint.IDEContext.pas index 0130b6ff..e2ce982f 100644 --- a/client/source/DelphiLint.IDEContext.pas +++ b/client/source/DelphiLint.IDEContext.pas @@ -359,7 +359,7 @@ procedure TToolsApiServices.ApplyTheme(Component: TComponent); procedure TToolsApiServices.RegisterFormClass(FormClass: TCustomFormClass); begin - (BorlandIDEServices as IOTAIDEThemingServices).RegisterFormClass(FormClass); + (BorlandIDEServices as IOTAIDEThemingServices250).RegisterFormClass(FormClass); end; //______________________________________________________________________________________________________________________ diff --git a/client/source/DelphiLint.OptionsForm.dfm b/client/source/DelphiLint.OptionsForm.dfm index db4a7e23..caa9c88e 100644 --- a/client/source/DelphiLint.OptionsForm.dfm +++ b/client/source/DelphiLint.OptionsForm.dfm @@ -176,7 +176,6 @@ object LintOptionsForm: TLintOptionsForm Items.Strings = ( 'Standalone' 'Connected (SonarQube)') - ShowFrame = False TabOrder = 0 OnClick = AnalysisModeGroupClick end diff --git a/client/source/DelphiLint.OptionsForm.pas b/client/source/DelphiLint.OptionsForm.pas index 7ece54fe..735fd00b 100644 --- a/client/source/DelphiLint.OptionsForm.pas +++ b/client/source/DelphiLint.OptionsForm.pas @@ -188,7 +188,7 @@ procedure TLintOptionsForm.RefreshTheme; WindowColor: TColor; begin LintContext.IDEServices.ApplyTheme(Self); - WindowColor := StyleServices(Self).GetSystemColor(clWindow); + WindowColor := StyleServices.GetSystemColor(clWindow); ContentPanel.Color := WindowColor; end; diff --git a/client/source/DelphiLint.Plugin.pas b/client/source/DelphiLint.Plugin.pas index 5d7bd7bd..8d2ff5ff 100644 --- a/client/source/DelphiLint.Plugin.pas +++ b/client/source/DelphiLint.Plugin.pas @@ -29,7 +29,11 @@ interface , Vcl.Menus , Vcl.Forms , DelphiLint.Handlers +{$IF CompilerVersion < 33.0} + , DelphiLint.ToolFrame.Legacy +{$ELSE} , DelphiLint.ToolFrame +{$ENDIF} , DelphiLint.SettingsFrame , DelphiLint.OptionsForm , DelphiLint.Context diff --git a/client/source/DelphiLint.Properties.pas b/client/source/DelphiLint.Properties.pas index f4d24566..4e500a62 100644 --- a/client/source/DelphiLint.Properties.pas +++ b/client/source/DelphiLint.Properties.pas @@ -268,10 +268,10 @@ constructor TPropertiesFile.Create(Path: string); destructor TPropertiesFile.Destroy; var - Field: TPropFieldBase; + I: Integer; begin - for Field in FFields do begin - FreeAndNil(Field); + for I := 0 to Length(FFields) - 1 do begin + FreeAndNil(FFields[I]); end; inherited; diff --git a/client/source/DelphiLint.Resources.pas b/client/source/DelphiLint.Resources.pas index 73075c33..5a738b29 100644 --- a/client/source/DelphiLint.Resources.pas +++ b/client/source/DelphiLint.Resources.pas @@ -24,7 +24,11 @@ interface , Vcl.Graphics , Vcl.Imaging.pngimage , DelphiLint.Data +{$IF CompilerVersion < 33.0} + , DelphiLint.ToolFrame.Legacy +{$ELSE} , DelphiLint.ToolFrame +{$ENDIF} ; type diff --git a/client/source/DelphiLint.Server.pas b/client/source/DelphiLint.Server.pas index 919ba2eb..9d4d03a1 100644 --- a/client/source/DelphiLint.Server.pas +++ b/client/source/DelphiLint.Server.pas @@ -222,6 +222,11 @@ TLintServerThread = class(TThread) procedure RefreshServer; procedure ReleaseServer; end; +//______________________________________________________________________________________________________________________ + +{$IF CompilerVersion < 33.0} +function EscapedString(AValue: string): string; +{$ENDIF} //______________________________________________________________________________________________________________________ @@ -514,7 +519,7 @@ procedure TLintServer.OnAnalyzeResponse( begin Result := TObjectList.Create; for Index := 0 to Json.Count - 1 do begin - Result.Add(TLintIssue.CreateFromJson(Json[Index] as TJSONObject)); + Result.Add(TLintIssue.CreateFromJson(Json.Items[Index] as TJSONObject)); end; end; @@ -524,7 +529,7 @@ procedure TLintServer.OnAnalyzeResponse( begin SetLength(Result, Json.Count); for Index := 0 to Json.Count - 1 do begin - Result[Index] := Json[Index].Value; + Result[Index] := Json.Items[Index].Value; end; end; @@ -607,7 +612,7 @@ procedure TLintServer.OnRuleRetrieveResponse( Rules: TObjectDictionary; begin if Response.Category <> CRuleRetrieveResult then begin - ErrorMsg := Response.Data.AsType; + ErrorMsg := (Response.Data as TJSONString).Value; ErrorCat := Response.Category; Log.Warn('Rule retrieve returned error (%d): %s', [ErrorCat, ErrorMsg]); @@ -1009,7 +1014,7 @@ function TLintServerTcpConnection.DoReceiveMessage: TTaggedMessage; DataBuffer := TBytes(IdDataBuffer); - DataJsonValue := TJSONValue.ParseJSONValue(DataBuffer, 0, Length, True); + DataJsonValue := TJSONObject.ParseJSONValue(DataBuffer, 0, Length, True); Result := TTaggedMessage.Create(TLintMessage.Create(Category, DataJsonValue), Id); end; @@ -1027,7 +1032,11 @@ procedure TLintServerTcpConnection.DoSendMessage(Msg: TTaggedMessage); Message := Msg.Extract; if Assigned(Message.Data) then begin +{$IF CompilerVersion < 33.0} + DataBytes := TEncoding.UTF8.GetBytes(EscapedString(Message.Data.ToString)); +{$ELSE} DataBytes := TEncoding.UTF8.GetBytes(Message.Data.ToString); +{$ENDIF} FTcpClient.IOHandler.Write(Length(DataBytes)); for DataByte in DataBytes do begin @@ -1123,4 +1132,25 @@ function TTaggedMessage.Extract: TLintMessage; FMessage := nil; end; +//______________________________________________________________________________________________________________________ + +{$IF CompilerVersion < 33.0} +function EscapedString(AValue: string): string; +begin + if AValue.StartsWith('"') then + AValue := AValue.Substring(1, AValue.Length-2); + + // Handle these special characters: \, ", #$8, #$9, #$a, #$c, #$d + Result := AValue + .Replace('\', '\\') + .Replace(#$8, '\b') + .Replace(#$9, '\t') + .Replace(#$a, '\n') + .Replace(#$c, '\f') + .Replace(#$d, '\r'); + + Log.Info('ToString: ' + Result); +end; +{$ENDIF} + end. diff --git a/client/source/DelphiLint.Settings.pas b/client/source/DelphiLint.Settings.pas index 92551017..38abdf7b 100644 --- a/client/source/DelphiLint.Settings.pas +++ b/client/source/DelphiLint.Settings.pas @@ -215,16 +215,16 @@ procedure TLintSettings.SyncTokenMap; begin FTokensMap.Clear; - HostTokenPairs := SplitString(SonarHostTokens, ','); + HostTokenPairs := TArray(SplitString(SonarHostTokens, ',')); for Pair in HostTokenPairs do begin - SplitPair := SplitString(Pair, '='); + SplitPair := TArray(SplitString(Pair, '=')); if Length(SplitPair) <> 2 then begin Log.Warn('Skipping invalid value ''%s'' in Sonar token mapping', [Pair]); Continue; end; - SplitIdent := SplitString(SplitPair[0], '@'); + SplitIdent := TArray(SplitString(SplitPair[0], '@')); if Length(SplitPair) <> 2 then begin Log.Warn('Skipping invalid value for key ''%s'' in Sonar token mapping', [SplitPair[0]]); diff --git a/client/source/DelphiLint.SettingsFrame.dfm b/client/source/DelphiLint.SettingsFrame.dfm index ca46651f..5448ff7f 100644 --- a/client/source/DelphiLint.SettingsFrame.dfm +++ b/client/source/DelphiLint.SettingsFrame.dfm @@ -24,7 +24,6 @@ object LintSettingsFrame: TLintSettingsFrame Anchors = [akLeft, akTop, akRight, akBottom] RaggedRight = True TabOrder = 0 - StyleElements = [seFont, seClient] object GeneralSheet: TTabSheet Caption = 'General' object GeneralPanel: TPanel @@ -169,19 +168,12 @@ object LintSettingsFrame: TLintSettingsFrame Top = 26 Width = 453 Height = 49 - DefaultHeaderFont = False DoubleBuffered = False - HeaderFont.Charset = DEFAULT_CHARSET - HeaderFont.Color = clBtnText - HeaderFont.Height = -1 - HeaderFont.Name = 'Segoe UI' - HeaderFont.Style = [] ItemIndex = 0 Items.Strings = ( 'Use the default version' 'Use a specific version') ParentDoubleBuffered = False - ShowFrame = False TabOrder = 1 OnClick = SonarDelphiVersionRadioGroupClick end @@ -190,19 +182,12 @@ object LintSettingsFrame: TLintSettingsFrame Top = 130 Width = 221 Height = 49 - DefaultHeaderFont = False DoubleBuffered = False - HeaderFont.Charset = DEFAULT_CHARSET - HeaderFont.Color = clBtnText - HeaderFont.Height = -1 - HeaderFont.Name = 'Segoe UI' - HeaderFont.Style = [] ItemIndex = 0 Items.Strings = ( 'Use SonarDelphi'#39's default ruleset' 'Use a custom ruleset') ParentDoubleBuffered = False - ShowFrame = False TabOrder = 2 OnClick = StandaloneRulesRadioGroupClick end diff --git a/client/source/DelphiLint.SettingsFrame.pas b/client/source/DelphiLint.SettingsFrame.pas index 2df15393..1659ca1f 100644 --- a/client/source/DelphiLint.SettingsFrame.pas +++ b/client/source/DelphiLint.SettingsFrame.pas @@ -335,7 +335,7 @@ procedure TLintSettingsFrame.PopulateStandaloneRulesBox; Exit; end; - DisabledRules := SplitString(LintContext.Settings.StandaloneDisabledRules, ','); + DisabledRules := TArray(SplitString(LintContext.Settings.StandaloneDisabledRules, ',')); SortedRules := FStandaloneRules.Values.ToArray; TArray.Sort(SortedRules, TComparer.Construct( @@ -384,7 +384,7 @@ procedure TLintSettingsFrame.RetrieveReleases; SetLength(Releases, Json.Count); for Index := 0 to Json.Count - 1 do begin - ReleaseVersion := Json[Index].GetValue('tag_name'); + ReleaseVersion := Json.Items[Index].GetValue('tag_name'); if StartsStr('v', ReleaseVersion) and (Length(ReleaseVersion) > 1) then begin ReleaseVersion := Copy(ReleaseVersion, 2); diff --git a/client/source/DelphiLint.SetupForm.pas b/client/source/DelphiLint.SetupForm.pas index 2d229320..dc9bc198 100644 --- a/client/source/DelphiLint.SetupForm.pas +++ b/client/source/DelphiLint.SetupForm.pas @@ -162,7 +162,7 @@ procedure TLintSetupForm.RefreshTheme; WindowColor: TColor; begin LintContext.IDEServices.ApplyTheme(Self); - WindowColor := StyleServices(Self).GetSystemColor(clWindow); + WindowColor := StyleServices.GetSystemColor(clWindow); RightPanel.Color := WindowColor; end; diff --git a/client/source/DelphiLint.ToolFrame.Legacy.dfm b/client/source/DelphiLint.ToolFrame.Legacy.dfm new file mode 100644 index 00000000..8ee7bf98 --- /dev/null +++ b/client/source/DelphiLint.ToolFrame.Legacy.dfm @@ -0,0 +1,650 @@ +object LintToolFrame: TLintToolFrame + Left = 0 + Top = 0 + Width = 451 + Height = 305 + Align = alClient + DoubleBuffered = True + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -12 + Font.Name = 'Segoe UI' + Font.Style = [] + ParentDoubleBuffered = False + ParentFont = False + TabOrder = 0 + OnResize = FrameResize + object ContentPanel: TPanel + Left = 0 + Top = 50 + Width = 451 + Height = 228 + Align = alClient + BevelOuter = bvNone + ShowCaption = False + TabOrder = 0 + object IssueImage: TImage + Left = 4 + Top = 4 + Width = 16 + Height = 16 + end + object IssueMessageLabel: TLabel + Left = 24 + Top = 4 + Width = 97 + Height = 13 + Caption = 'Issue description' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWhite + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [fsBold] + ParentFont = False + Transparent = True + end + object IssueMetaLabel: TLabel + Left = 24 + Top = 17 + Width = 79 + Height = 15 + Caption = 'Issue metadata' + end + object ListView: TListView + Left = 0 + Top = 0 + Width = 178 + Height = 228 + Align = alClient + BevelInner = bvNone + BevelOuter = bvNone + BorderStyle = bsNone + Columns = < + item + AutoSize = True + end> + ColumnClick = False + HideSelection = False + IconOptions.WrapText = False + OwnerData = True + OwnerDraw = True + ReadOnly = True + RowSelect = True + ParentColor = True + ShowColumnHeaders = False + TabOrder = 3 + ViewStyle = vsReport + OnContextPopup = IssueControlListContextPopup + OnCustomDrawItem = ListViewCustomDrawItem + OnDblClick = IssueControlListItemDblClick + OnSelectItem = ListViewSelectItem + end + object RulePanel: TPanel + Left = 186 + Top = 0 + Width = 265 + Height = 228 + Align = alRight + BevelOuter = bvNone + ShowCaption = False + TabOrder = 0 + object RuleBrowser: TWebBrowser + Left = 0 + Top = 0 + Width = 265 + Height = 228 + Align = alClient + TabOrder = 0 + OnBeforeNavigate2 = RuleBrowserBeforeNavigate2 + OnNewWindow2 = RuleBrowserNewWindow2 + OnDocumentComplete = RuleBrowserDocumentComplete + ExplicitLeft = 104 + ExplicitTop = 104 + ExplicitWidth = 300 + ExplicitHeight = 150 + ControlData = { + 4C000000631B0000911700000000000000000000000000000000000000000000 + 000000004C000000000000000000000001000000E0D057007335CF11AE690800 + 2B2E126208000000000000004C0000000114020000000000C000000000000046 + 8000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000100000000000000000000000000000000000000} + end + end + object ResizeIndicatorPanel: TPanel + Left = 136 + Top = 17 + Width = 185 + Height = 41 + BevelOuter = bvNone + Caption = 'ResizeIndicatorPanel' + Color = clGray + UseDockManager = False + ParentBackground = False + ShowCaption = False + TabOrder = 1 + Visible = False + StyleElements = [] + end + object SplitPanel: TPanel + Left = 178 + Top = 0 + Width = 8 + Height = 228 + Cursor = crHSplit + Align = alRight + BevelOuter = bvNone + BorderWidth = 1 + Caption = 'SplitPanel' + ShowCaption = False + TabOrder = 2 + OnMouseDown = SplitPanelMouseDown + OnMouseMove = SplitPanelMouseMove + OnMouseUp = SplitPanelMouseUp + end + end + object StatusPanel: TPanel + Left = 0 + Top = 278 + Width = 451 + Height = 27 + Align = alBottom + BevelOuter = bvNone + ShowCaption = False + TabOrder = 1 + object ProgLabel: TLabel + AlignWithMargins = True + Left = 85 + Top = 3 + Width = 52 + Height = 21 + Align = alLeft + Caption = 'Analyzing' + Layout = tlCenter + ExplicitHeight = 15 + end + object ProgBar: TProgressBar + AlignWithMargins = True + Left = 6 + Top = 6 + Width = 73 + Height = 15 + Margins.Left = 6 + Margins.Top = 6 + Margins.Bottom = 6 + Align = alLeft + DoubleBuffered = True + Max = 10 + ParentDoubleBuffered = False + Position = 10 + Smooth = True + MarqueeInterval = 30 + SmoothReverse = True + Step = 1 + TabOrder = 0 + end + object ErrorButtonPanel: TPanel + Left = 319 + Top = 0 + Width = 132 + Height = 27 + Align = alRight + BevelOuter = bvNone + Color = clRed + ParentBackground = False + ShowCaption = False + TabOrder = 1 + object ErrorButton: TSpeedButton + Left = 0 + Top = 0 + Width = 132 + Height = 27 + Align = alClient + Caption = '2 Errors' + Flat = True + Font.Charset = DEFAULT_CHARSET + Font.Color = clWhite + Font.Height = -12 + Font.Name = 'Segoe UI' + Font.Style = [fsBold] + ParentFont = False + StyleElements = [seFont, seClient] + OnClick = ViewLogClick + ExplicitLeft = 64 + ExplicitWidth = 23 + ExplicitHeight = 22 + end + end + object WarningButtonPanel: TPanel + Left = 187 + Top = 0 + Width = 132 + Height = 27 + Align = alRight + BevelOuter = bvNone + Color = 42495 + ParentBackground = False + ShowCaption = False + TabOrder = 2 + object WarningButton: TSpeedButton + Left = 0 + Top = 0 + Width = 132 + Height = 27 + Align = alClient + Caption = '2 Warnings' + Flat = True + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -12 + Font.Name = 'Segoe UI' + Font.Style = [fsBold] + ParentFont = False + StyleElements = [seFont, seClient] + OnClick = ViewLogClick + ExplicitLeft = 64 + ExplicitWidth = 23 + ExplicitHeight = 22 + end + end + end + object TopPanel: TPanel + Left = 0 + Top = 0 + Width = 451 + Height = 50 + Align = alTop + BevelOuter = bvNone + ShowCaption = False + TabOrder = 2 + object FileHeadingPanel: TPanel + Left = 0 + Top = 0 + Width = 451 + Height = 50 + Align = alClient + BevelOuter = bvNone + ShowCaption = False + TabOrder = 0 + DesignSize = ( + 451 + 50) + object FileNameLabel: TLabel + Left = 30 + Top = 10 + Width = 87 + Height = 15 + Caption = 'No file selected' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -12 + Font.Name = 'Segoe UI' + Font.Style = [fsBold] + ParentFont = False + Layout = tlCenter + end + object ProgImage: TImage + Left = 9 + Top = 10 + Width = 16 + Height = 16 + Proportional = True + end + object FileStatusLabel: TLabel + Left = 30 + Top = 26 + Width = 52 + Height = 15 + Caption = 'Analyzing' + Layout = tlCenter + end + object LintButtonPanel: TPanel + Left = 367 + Top = 0 + Width = 84 + Height = 50 + Align = alRight + BevelOuter = bvNone + ShowCaption = False + TabOrder = 0 + end + object LintToolBar: TToolBar + Left = 351 + Top = 11 + Width = 94 + Height = 29 + Align = alNone + Anchors = [akTop, akRight] + ButtonHeight = 29 + ButtonWidth = 59 + Caption = 'LintToolBar' + List = True + ShowCaptions = True + TabOrder = 1 + object AnalyzeShortButton: TToolButton + Left = 0 + Top = 0 + Action = PluginCore.ActionAnalyzeShort + DropdownMenu = AnalyzePopupMenu + Style = tbsDropDown + end + end + end + end + object WebViewInitTimer: TTimer + Interval = 200 + OnTimer = WebViewInitTimerTimer + Left = 56 + Top = 128 + end + object ErrorImageList: TImageList + Left = 52 + Top = 178 + Bitmap = { + 494C010104000900040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 + 0000000000003600000028000000400000002000000001002000000000000020 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000F0FBFF00F0FBFF00F0FBFF00F0FB + FF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FB + FF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FB + FF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00000000000000 + 00000000000000000000F0FBFF00F0FBFF000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000F0FBFF00F0FBFF00F0FBFF00F0FB + FF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FB + FF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FB + FF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF00F0FBFF0000000000F0FB + FF00F0FBFF00F0FBFF00F0FBFF00F0FBFF000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000F0FBFF00F0FBFF000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000F0FBFF00F0FBFF000000000000000000F0FBFF00F0FBFF000000 + 000000000000000000000000000000000000000000000000000000000000F0FB + FF000000000000000000F0FBFF00000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000F0FBFF00F0FBFF000000 + 0000000000000000000000000000F0FBFF00F0FBFF0000000000000000000000 + 000000000000F0FBFF00F0FBFF000000000000000000F0FBFF00F0FBFF000000 + 0000000000000000000000000000F0FBFF00F0FBFF000000000000000000F0FB + FF000000000000000000F0FBFF00000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000F0FBFF00F0FB + FF00000000000000000000000000F0FBFF00F0FBFF0000000000000000000000 + 0000F0FBFF00F0FBFF0000000000000000000000000000000000F0FBFF00F0FB + FF00000000000000000000000000F0FBFF00F0FBFF000000000000000000F0FB + FF00F0FBFF00F0FBFF00F0FBFF00000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000F0FBFF00F0FB + FF000000000000000000000000008D8EE2008D8EE20000000000000000000000 + 0000F0FBFF00F0FBFF0000000000000000000000000000000000F0FBFF00F0FB + FF000000000000000000000000008D8EE2008D8EE20000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000002080D4002080D40000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000002080D4002080D40000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000F0FB + FF00F0FBFF000000000000000000F0FBFF00F0FBFF000000000000000000F0FB + FF00F0FBFF00000000000000000000000000000000000000000000000000F0FB + FF00F0FBFF000000000000000000F0FBFF00F0FBFF000000000000000000F0FB + FF00F0FBFF000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000F0FB + FF00F0FBFF000000000000000000F0FBFF00F0FBFF000000000000000000F0FB + FF00F0FBFF00000000000000000000000000000000000000000000000000F0FB + FF00F0FBFF000000000000000000F0FBFF00F0FBFF000000000000000000F0FB + FF00F0FBFF000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000F0FBFF00F0FBFF0000000000F0FBFF00F0FBFF0000000000F0FBFF00F0FB + FF00000000000000000000000000000000000000000000000000000000000000 + 0000F0FBFF00F0FBFF0000000000F0FBFF00F0FBFF0000000000F0FBFF00F0FB + FF00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000F0FBFF00F0FBFF0000000000F0FBFF00F0FBFF0000000000F0FBFF00F0FB + FF00000000000000000000000000000000000000000000000000000000000000 + 0000F0FBFF00F0FBFF0000000000F0FBFF00F0FBFF0000000000F0FBFF00F0FB + FF00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000F0FBFF00F0FBFF000000000000000000F0FBFF00F0FBFF000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000F0FBFF00F0FBFF000000000000000000F0FBFF00F0FBFF000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000F0FBFF00F0FBFF000000000000000000F0FBFF00F0FBFF000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000F0FBFF00F0FBFF000000000000000000F0FBFF00F0FBFF000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000F0FBFF00F0FBFF00F0FBFF00F0FBFF00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000F0FBFF00F0FBFF00F0FBFF00F0FBFF00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000F0FBFF00F0FBFF00F0FBFF00F0FBFF00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000F0FBFF00F0FBFF00F0FBFF00F0FBFF00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000F0FBFF00F0FBFF0000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000F0FBFF00F0FBFF0000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000F0FBFF00F0FBFF0000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000F0FBFF00F0FBFF0000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000424D3E000000000000003E000000 + 2800000040000000200000000100010000000000000100000000000000000000 + 000000000000000000000000FFFFFF0000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000003C0000003C0000002000000020 + 9FF99FED9FF99FED9E799E6D9E799E6DCE73CE61CE73CE61CE73CE7FCE73CE7F + E667E667E667E667E667E667E667E667F24FF24FF24FF24FF24FF24FF24FF24F + F99FF99FF99FF99FF99FF99FF99FF99FFC3FFC3FFC3FFC3FFC3FFC3FFC3FFC3F + FE7FFE7FFE7FFE7FFE7FFE7FFE7FFE7F00000000000000000000000000000000 + 000000000000} + end + object AnalyzePopupMenu: TPopupMenu + Images = PluginCore.LintImages + Left = 52 + Top = 230 + object AnalyzeCurrentFile1: TMenuItem + Action = PluginCore.ActionAnalyzeActiveFile + end + object AnalyzeOpenFiles1: TMenuItem + Action = PluginCore.ActionAnalyzeOpenFiles + end + object Separator1: TMenuItem + Caption = '-' + end + object ActionClearActiveFile1: TMenuItem + Action = PluginCore.ActionClearActiveFile + end + object Separator2: TMenuItem + Caption = '-' + end + object ViewLogItem: TMenuItem + Caption = '&View Last Analysis Log' + OnClick = ViewLogClick + end + end + object IssueContextMenu: TPopupMenu + MenuAnimation = [maNone] + Left = 56 + Top = 66 + end + object MarqueeTimer: TTimer + Enabled = False + Interval = 100 + OnTimer = MarqueeTimerTimer + Left = 216 + Top = 152 + end +end diff --git a/client/source/DelphiLint.ToolFrame.Legacy.pas b/client/source/DelphiLint.ToolFrame.Legacy.pas new file mode 100644 index 00000000..13b51a7e --- /dev/null +++ b/client/source/DelphiLint.ToolFrame.Legacy.pas @@ -0,0 +1,1076 @@ +{ +DelphiLint Client +Copyright (C) 2024 Integrated Application Development + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +} +unit DelphiLint.ToolFrame.Legacy; + +interface + +uses + System.Classes + , System.Generics.Collections + , Vcl.Controls + , Vcl.Forms + , Vcl.ComCtrls + , Vcl.ExtCtrls + , Vcl.StdCtrls + , Vcl.Menus + , Vcl.ToolWin + , Vcl.OleCtrls + , SHDocVw + , Winapi.Windows + , DelphiLint.Data + , DelphiLint.IDEBaseTypes + , DelphiLint.HtmlGen + , DelphiLint.Utils + , DelphiLint.Context + , DelphiLint.LiveData + , Vcl.Buttons + , System.ImageList + , Vcl.ImgList + ; + +type + TCurrentFileStatus = ( + cfsNotAnalyzable, + cfsNotAnalyzed, + cfsInAnalysis, + cfsFailed, + cfsNoIssues, + cfsNoIssuesOutdated, + cfsIssues, + cfsIssuesOutdated + ); + + TLintToolFrame = class(TFrame) + ContentPanel: TPanel; + RulePanel: TPanel; + StatusPanel: TPanel; + ProgBar: TProgressBar; + ProgLabel: TLabel; + ResizeIndicatorPanel: TPanel; + SplitPanel: TPanel; + TopPanel: TPanel; + WebViewInitTimer: TTimer; + ErrorImageList: TImageList; + ErrorButtonPanel: TPanel; + WarningButtonPanel: TPanel; + WarningButton: TSpeedButton; + ErrorButton: TSpeedButton; + AnalyzePopupMenu: TPopupMenu; + AnalyzeCurrentFile1: TMenuItem; + AnalyzeOpenFiles1: TMenuItem; + Separator1: TMenuItem; + ActionClearActiveFile1: TMenuItem; + Separator2: TMenuItem; + ViewLogItem: TMenuItem; + IssueContextMenu: TPopupMenu; + ListView: TListView; + IssueImage: TImage; + IssueMessageLabel: TLabel; + IssueMetaLabel: TLabel; + FileHeadingPanel: TPanel; + FileNameLabel: TLabel; + ProgImage: TImage; + FileStatusLabel: TLabel; + LintButtonPanel: TPanel; + LintToolBar: TToolBar; + AnalyzeShortButton: TToolButton; + RuleBrowser: TWebBrowser; + MarqueeTimer: TTimer; + procedure BtnNavigateClick(Sender: TObject); + procedure SplitPanelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer); + procedure SplitPanelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer); + procedure SplitPanelMouseMove(Sender: TObject; Shift: TShiftState; X: Integer; Y: Integer); + procedure RuleBrowserBeforeNavigate2(Sender: TObject; const pDisp: IDispatch; + const URL, Flags, TargetFrameName, PostData, Headers: OleVariant; var Cancel: WordBool); + procedure RuleBrowserNewWindow2(Sender: TObject; var ppDisp: IDispatch; var Cancel: WordBool); + procedure RuleBrowserDocumentComplete(Sender: TObject; const pDisp: IDispatch; const URL: OleVariant); + procedure FrameResize(Sender: TObject); + procedure IssueControlListContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); + procedure ListViewCustomDrawItem(Sender: TCustomListView; Item: TListItem; + State: TCustomDrawState; var DefaultDraw: Boolean); + procedure ListViewSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean); + procedure IssueControlListItemDblClick(Sender: TObject); + procedure MarqueeTimerTimer(Sender: TObject); + procedure ViewLogClick(Sender: TObject); + procedure WebViewInitTimerTimer(Sender: TObject); + private const + CIssueStatusStrs: array[TIssueStatus] of string = ( + 'Open', + 'Confirmed', + 'Reopened', + 'Resolved', + 'Closed', + 'Accepted', + 'To review', + 'Reviewed (acknowledged)' + ); + private + FResizing: Boolean; + FDragStartX: Integer; + FCurrentPath: string; + FIssues: TObjectList>; + FRuleHtmls: TDictionary; + FLastAnalysisLogs: TArray; + FLastAnalysisTime: TDateTime; + FVisibleRule: string; + FNavigationAllowed: Boolean; + FRuleHtmlGenerator: TRuleHtmlGenerator; + FBrowserHwnd: HWND; + + function GetSelectedIssue: ILiveIssue; + procedure UpdateFileNameLabel(NewText: string = ''); + + procedure RefreshIssueView; + function GetIssueMetadataText(Issue: ILiveIssue): string; + + procedure SetRuleView(Rule: TRule); + + procedure OnAnalysisStateChanged(const StateChange: TAnalysisStateChangeContext); + procedure OnAnalysisStarted(const Paths: TArray); + procedure OnAnalysisFinished(const Paths: TArray; const Succeeded: Boolean); + + procedure RefreshRuleView; + procedure DirtyWebView; + + function GetStatusCaption(Status: TCurrentFileStatus; NumIssues: Integer): string; + procedure UpdateFileStatus(Status: TCurrentFileStatus; NumIssues: Integer = -1); + procedure UpdateAnalysisStatus(Msg: string; ShowProgress: Boolean = False); + procedure UpdateAnalysisStatusForFile(const Path: string); + + procedure SetLogMessages(LogMessages: TArray); + + function CreateIssuePopup(Index: Integer): TPopupMenu; + procedure OpenRuleInBrowser(Sender: TObject); + public + constructor Create(Owner: TComponent); override; + destructor Destroy; override; + + procedure ChangeActiveFile(const Path: string); + procedure RefreshActiveFile; + end; + + TLintToolFormInfo = class(TCustomDockableFormBase) + public + function GetCaption: string; override; + function GetIdentifier: string; override; + function GetFrameClass: TCustomFrameClass; override; + procedure FrameCreated(AFrame: TCustomFrame); override; + end; + +implementation + +uses + System.SysUtils + , System.DateUtils + , System.TimeSpan + , System.StrUtils + , System.IOUtils + , System.Types + , System.UITypes + , System.Win.ComObj + , Vcl.Dialogs + , Vcl.Graphics + , Winapi.ShellAPI + , DelphiLint.Resources + , DelphiLint.IssueActions + , DelphiLint.LogViewer + , System.Variants + , System.RegularExpressions + ; + +{$R *.dfm} + +procedure AssignCleanImageToButtonGlyph(Button: TSpeedButton; ImageList: TCustomImageList; Index: Integer); +var + Bmp: Vcl.Graphics.TBitmap; + R: TRect; +begin + Bmp := Vcl.Graphics.TBitmap.Create; + try + Bmp.PixelFormat := pf24bit; + Bmp.SetSize(ImageList.Width, ImageList.Height); + + Bmp.Canvas.Brush.Color := clFuchsia; + R := Rect(0, 0, Bmp.Width, Bmp.Height); + Bmp.Canvas.FillRect(R); + + ImageList.Draw(Bmp.Canvas, 0, 0, Index, True); + + Button.Glyph.Assign(Bmp); + Button.Glyph.Transparent := True; + Button.Glyph.TransparentColor := clFuchsia; + Button.NumGlyphs := 1; + finally + Bmp.Free; + end; +end; + +constructor TLintToolFrame.Create(Owner: TComponent); +var + Editor: IIDESourceEditor; +begin + inherited Create(Owner); + + ListView.SmallImages := TImageList.Create(Self); + ListView.SmallImages.Height := 40; + + AssignCleanImageToButtonGlyph(WarningButton, ErrorImageList, 2); + AssignCleanImageToButtonGlyph(ErrorButton, ErrorImageList, 0); + + FResizing := False; + FCurrentPath := ExtractFilePath(ParamStr(0)); + FNavigationAllowed := False; + FRuleHtmls := TDictionary.Create; + + FRuleHtmlGenerator := TRuleHtmlGenerator.Create; + + FIssues := TObjectList>.Create; + + FBrowserHwnd := RuleBrowser.Handle; + RuleBrowser.Navigate('about:blank'); + + + Analyzer.OnAnalysisStateChanged.AddListener(OnAnalysisStateChanged); + + if TryGetCurrentSourceEditor(Editor) then begin + ChangeActiveFile(Editor.FileName); + end + else begin + ChangeActiveFile(''); + end; + + if Analyzer.InAnalysis then begin + OnAnalysisStarted(Analyzer.CurrentAnalysis.Paths); + end + else begin + UpdateAnalysisStatus('Idle'); + end; + + DirtyWebView; + + SetLogMessages([]); + + LintContext.Plugin.OnActiveFileChanged.AddListener(ChangeActiveFile); +end; + +//______________________________________________________________________________________________________________________ + +function TLintToolFrame.CreateIssuePopup(Index: Integer): TPopupMenu; + + function DummyMenuItem(Owner: TComponent): TMenuItem; + begin + Result := TMenuItem.Create(Owner); + Result.Visible := False; + end; + +var + Issue: ILiveIssue; + MenuItemFactory: TIssueMenuItemFactory; + Item: TMenuItem; + I: Integer; +begin + if (Index < 0) or (Index >= FIssues.Count) then begin + Result := nil; + Exit; + end; + + Result := IssueContextMenu; + + for I := Result.Items.Count - 1 downto 0 do begin + Result.Items[I].Free; + end; + + Item := TMenuItem.Create(Self); + Item.Caption := 'Open Rule in Browser'; + Item.OnClick := OpenRuleInBrowser; + Result.Items.Add(Item); + Item := TMenuItem.Create(Self); + Item.Caption := '-'; + Result.Items.Add(Item); + + Issue := FIssues[Index].Get; + MenuItemFactory := TIssueMenuItemFactory.Create(Issue); + try + Result.Items.Add(DummyMenuItem(Result)); + Result.Items.Add(MenuItemFactory.HideIssue(Result)); + + Item := MenuItemFactory.ApplyQuickFix(Result); + if Assigned(Item) then begin + Result.Items.Add(Item); + end; + finally + FreeAndNil(MenuItemFactory); + end; +end; + +procedure TLintToolFrame.OpenRuleInBrowser(Sender: TObject); +var + SelectedIssue: ILiveIssue; + Rule: TRule; + HtmlFilePath: string; +begin + SelectedIssue := GetSelectedIssue; + + if Assigned(SelectedIssue) then begin + Rule := Analyzer.GetRule(SelectedIssue.RuleKey); + if Assigned(Rule) then + begin + if (not FRuleHtmls.ContainsKey(Rule.RuleKey)) or (not FileExists(FRuleHtmls[Rule.RuleKey])) then begin + FRuleHtmls.AddOrSetValue(Rule.RuleKey, FRuleHtmlGenerator.GenerateHtmlFile(Rule)); + end; + + HtmlFilePath := FRuleHtmls[Rule.RuleKey]; + ShellExecute(0, 'open', PChar(NormalizePath(HtmlFilePath)), nil, nil, SW_SHOWNORMAL); + end; + end; +end; + +//______________________________________________________________________________________________________________________ + +destructor TLintToolFrame.Destroy; +begin + FreeAndNil(FRuleHtmls); + FreeAndNil(FRuleHtmlGenerator); + FreeAndNil(FIssues); + inherited; +end; + +procedure TLintToolFrame.BtnNavigateClick(Sender: TObject); +var + LURL: string; +begin + LURL := InputBox('URL: ', 'Navegar', 'file:///'); + FNavigationAllowed := True; + RuleBrowser.Navigate(LURL); + SplitPanel.Visible := True; + RulePanel.Visible := True; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.ViewLogClick(Sender: TObject); +var + Form: TLogViewerForm; +begin + Form := TLogViewerForm.Create(nil, FLastAnalysisTime, FLastAnalysisLogs); + try + LintContext.IDEServices.ApplyTheme(Form); + Form.ShowModal; + finally + FreeAndNil(Form); + end; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.FrameResize(Sender: TObject); +begin + if RulePanel.Left < 10 then begin + RulePanel.Width := Width div 2; + end; + + DirtyWebView; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.UpdateAnalysisStatus(Msg: string; ShowProgress: Boolean); +begin + MarqueeTimer.Enabled := ShowProgress; + ProgBar.Position := 0; + ProgLabel.Caption := Msg; + Repaint; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.OnAnalysisStarted(const Paths: TArray); +var + SourceFile: string; +begin + if Length(Paths) = 2 then begin + SourceFile := Paths[0]; + if IsDelphiSource(Paths[1]) then begin + SourceFile := Paths[1]; + end; + + UpdateAnalysisStatus(Format('Analyzing %s...', [TPath.GetFileName(SourceFile)]), True); + end + else begin + for SourceFile in Paths do begin + if IsDelphiSource(SourceFile) then begin + Break; + end; + end; + + UpdateAnalysisStatus( + Format( + 'Analyzing %s + %d more...', + [TPath.GetFileName(SourceFile), Length(Paths) - 2]), + True); + end; + + RefreshActiveFile; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.OnAnalysisStateChanged(const StateChange: TAnalysisStateChangeContext); +begin + case StateChange.Change of + ascStarted: begin + OnAnalysisStarted(StateChange.Files); + end; + ascSucceeded: begin + SetLogMessages(StateChange.LogMessages); + OnAnalysisFinished(StateChange.Files, True); + end; + ascFailed: begin + OnAnalysisFinished(StateChange.Files, False); + end; + ascCleared: begin + ChangeActiveFile(FCurrentPath); + end; + ascUpdated: begin + ChangeActiveFile(FCurrentPath); + end; + end; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.OnAnalysisFinished(const Paths: TArray; const Succeeded: Boolean); +begin + UpdateAnalysisStatus( + Format( + 'Idle (last analysis%s at %s)', + [IfThen(Succeeded, '', 'failed'), FormatDateTime('h:nnam/pm', Now)])); + RefreshActiveFile; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.SplitPanelMouseDown( + Sender: TObject; + Button: TMouseButton; + Shift: TShiftState; + X: Integer; + Y: Integer); +begin + if Button <> mbLeft then begin + Exit; + end; + + FResizing := True; + FDragStartX := X; + ResizeIndicatorPanel.Visible := True; + ResizeIndicatorPanel.BoundsRect := SplitPanel.BoundsRect; + ResizeIndicatorPanel.BringToFront; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.SplitPanelMouseMove(Sender: TObject; Shift: TShiftState; X: Integer; Y: Integer); +begin + if not FResizing then begin + Exit; + end; + + ResizeIndicatorPanel.Left := SplitPanel.Left + X; + ListView.Invalidate; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.SplitPanelMouseUp( + Sender: TObject; + Button: TMouseButton; + Shift: TShiftState; + X: Integer; + Y: Integer); +var + NewWidth: Integer; +begin + if (Button <> mbLeft) or (not FResizing) then begin + Exit; + end; + + FResizing := False; + ResizeIndicatorPanel.Visible := False; + NewWidth := RulePanel.Width - (X - FDragStartX); + + if (NewWidth < ContentPanel.Width - 10) then begin + RulePanel.Width := NewWidth; + end; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.UpdateFileNameLabel(NewText: string = ''); +begin + if NewText = '' then begin + FileNameLabel.Caption := TPath.GetFileName(FCurrentPath); + end + else begin + FileNameLabel.Caption := NewText; + end; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.ChangeActiveFile(const Path: string); +var + FileScannable: Boolean; +begin + FileScannable := IsFileInProject(Path); + FCurrentPath := IfThen(FileScannable, Path, ''); + + if FileScannable then begin + if Analyzer.InAnalysis and Analyzer.CurrentAnalysis.IncludesFile(Path) then begin + UpdateFileStatus(cfsInAnalysis); + Exit; + end; + + UpdateAnalysisStatusForFile(Path); + end + else begin + UpdateFileStatus(cfsNotAnalyzable); + end; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.UpdateAnalysisStatusForFile(const Path: string); + + procedure UpdateAnalyzedFileStatus(const Path: string; Outdated: Boolean); + var + History: TFileAnalysisHistory; + begin + if not Analyzer.TryGetAnalysisHistory(Path, History) then begin + Log.Warn('Could not get analysis history for file %s with apparently outdated analysis', [Path]); + UpdateFileStatus(cfsNotAnalyzed); + Exit; + end; + + if not History.Success then begin + UpdateFileStatus(cfsNotAnalyzed); + end; + + if Outdated then begin + if History.IssuesFound = 0 then begin + UpdateFileStatus(cfsNoIssuesOutdated); + end + else begin + UpdateFileStatus(cfsIssuesOutdated, History.IssuesFound); + end; + end + else begin + if History.IssuesFound = 0 then begin + UpdateFileStatus(cfsNoIssues); + end + else begin + UpdateFileStatus(cfsIssues, History.IssuesFound); + end; + end; + end; + +begin + case Analyzer.GetAnalysisStatus(Path) of + fasOutdatedAnalysis: + UpdateAnalyzedFileStatus(Path, True); + fasUpToDateAnalysis: + UpdateAnalyzedFileStatus(Path, False); + else + UpdateFileStatus(cfsNotAnalyzed); + end; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.UpdateFileStatus(Status: TCurrentFileStatus; NumIssues: Integer = -1); +begin + if Status = TCurrentFileStatus.cfsNotAnalyzable then begin + UpdateFileNameLabel('Non-project file'); + end + else begin + UpdateFileNameLabel; + end; + + ProgImage.Picture.Graphic := LintResources.LintStatusIcon(Status); + FileStatusLabel.Caption := GetStatusCaption(Status, NumIssues); + RefreshIssueView; +end; + +//______________________________________________________________________________________________________________________ + +function TLintToolFrame.GetSelectedIssue: ILiveIssue; +var + SelectedIndex: Integer; +begin + SelectedIndex := ListView.ItemIndex; + if SelectedIndex = -1 then begin + Result := nil; + end + else if (SelectedIndex >= 0) and (SelectedIndex < FIssues.Count) then begin + Result := FIssues[SelectedIndex].Get; + end + else begin + Log.Warn('Issue %d was selected in control list, but there were only %d issues', [SelectedIndex, FIssues.Count]); + Result := nil; + end; +end; + +//______________________________________________________________________________________________________________________ + +function TLintToolFrame.GetStatusCaption(Status: TCurrentFileStatus; NumIssues: Integer): string; +begin + case Status of + cfsNotAnalyzable: Result := 'Not analyzable'; + cfsNotAnalyzed: Result := 'Not analyzed'; + cfsInAnalysis: Result := 'Analyzing'; + cfsFailed: Result := 'Failed'; + cfsNoIssues: Result := 'No issues'; + cfsNoIssuesOutdated: Result := 'No issues (outdated)'; + cfsIssues: begin + if NumIssues = 1 then begin + Result := '1 issue'; + end + else begin + Result := Format('%d issues', [NumIssues]); + end; + end; + cfsIssuesOutdated: + if NumIssues = 1 then begin + Result := '1 issue (outdated)'; + end + else begin + Result := Format('%d issues (outdated)', [NumIssues]); + end; + else + Result := 'Not analyzable'; + end; +end; + +//______________________________________________________________________________________________________________________ + +function TLintToolFrame.GetIssueMetadataText(Issue: ILiveIssue): string; +var + CreationTimeString: string; + CreationDateTime: TDateTime; + TimeSinceCreation: TTimeSpan; + ExtraInfo: string; +begin + Result := Format('(%d, %d)', [Issue.StartLine, Issue.StartLineOffset]); + + if Issue.HasMetadata then begin + if Issue.CreationDate <> '' then begin + CreationTimeString := TRegEx.Replace(Issue.CreationDate, '([+-]\d{2})(\d{2})$', '$1:$2'); + CreationDateTime := ISO8601ToDate(CreationTimeString, False); + TimeSinceCreation := TTimeSpan.Subtract(Now, CreationDateTime); + + ExtraInfo := Format('%s • %s • %s', [ + TimeSpanToAgoString(TimeSinceCreation), + CIssueStatusStrs[Issue.Status], + IfThen(Issue.Assignee <> '', 'Assigned to ' + Issue.Assignee, 'Unassigned') + ]); + end + else begin + ExtraInfo := 'New issue'; + end; + end + else begin + ExtraInfo := 'New issue'; + end; + + Result := Format('%s • %s', [Result, ExtraInfo]); + + if not Issue.IsTethered then begin + Result := Format('%s • %s', [Result, 'Potentially resolved']); + end; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.WebViewInitTimerTimer(Sender: TObject); +begin + WebViewInitTimer.Enabled := False; + + if FBrowserHwnd <> RuleBrowser.Handle then begin + // Docking or undocking the DelphiLint frame sometimes "detaches" the web view from the control, resulting in + // a blank white control. The browser handle changes when the frame is docker or undocked, and it seems like + // the only reliable indicator that this could have happened. There are many false positives with this approach, + // but since the effect isn't too disruptive it's an acceptable solution. + + Log.Debug('Dirty check found change in handle (%x to %x) - initializing', [FBrowserHwnd, RuleBrowser.Handle]); + FBrowserHwnd := RuleBrowser.Handle; + end; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.DirtyWebView; +begin + // Starting the IDE with a window layout including a docked DelphiLint can sometimes cause the web view to fail + // to initialize (likely because the windows are not properly registered with Windows yet). This initializes the + // web view after a short delay managed by the VCL event loop instead, circumventing this issue. + // + // Also, since DirtyWebView is called on frame resize, delaying a short period helps prevent excessive web view + // reinitializations. + + WebViewInitTimer.Enabled := True; +end; + +procedure TLintToolFrame.ListViewCustomDrawItem(Sender: TCustomListView; Item: TListItem; + State: TCustomDrawState; var DefaultDraw: Boolean); +var + Issue: ILiveIssue; + Rule: TRule; + MaxImpactSeverity: TImpactSeverity; + ImageRect: TRect; + MessageRect: TRect; + MessageTextHeight: Integer; + MetaRect: TRect; + MetaTextHeight: Integer; + TextStartX: Integer; + CurrentY: Integer; + IssueMessageText: string; + IssueMetaText: string; +begin + DefaultDraw := False; + + Issue := FIssues[Item.Index].Get; + + if Item.Index >= FIssues.Count then + Exit; + + if Item.Selected then + begin + Sender.Canvas.Brush.Color := clHighlight; + Sender.Canvas.Font.Color := clHighlightText; + end + else + begin + Sender.Canvas.Brush.Color := TListView(Sender).Color; + Sender.Canvas.Font.Color := TListView(Sender).Font.Color; + end; + Sender.Canvas.FillRect(Item.DisplayRect(drBounds)); + + Rule := Analyzer.GetRule(Issue.RuleKey); + if not Assigned(Rule) then begin + Log.Warn('Rule "%s" could not be drawn', [Issue.RuleKey]); + IssueImage.Picture.Graphic := nil; + end + else + begin + if Assigned(Rule.CleanCode) then + begin + MaxImpactSeverity := TArrayUtils.Max(Rule.CleanCode.Impacts.Values.ToArray, imsMedium); + IssueImage.Picture.Graphic := LintResources.ImpactSeverityIcon(MaxImpactSeverity); + end + else + begin + IssueImage.Picture.Graphic := LintResources.RuleTypeIcon(Rule.RuleType, Rule.Severity); + end; + + if Assigned(IssueImage.Picture.Graphic) then + begin + ImageRect := Rect(Item.DisplayRect(drBounds).Left + 2, Item.DisplayRect(drBounds).Top + 2, + Item.DisplayRect(drBounds).Left + IssueImage.Width + 2, + Item.DisplayRect(drBounds).Top + IssueImage.Height + 2); + Sender.Canvas.Draw(ImageRect.Left, ImageRect.Top, IssueImage.Picture.Graphic); + end; + end; + + TextStartX := Item.DisplayRect(drBounds).Left + IssueImage.Width + 8; + CurrentY := Item.DisplayRect(drBounds).Top + 2; + + Sender.Canvas.Font.Assign(IssueMessageLabel.Font); + IssueMessageText := Issue.Message; + MessageTextHeight := Sender.Canvas.TextHeight(IssueMessageText); + + MessageRect := Rect(TextStartX, CurrentY, + Item.DisplayRect(drBounds).Right - 4, CurrentY + MessageTextHeight); + Sender.Canvas.TextRect(MessageRect, IssueMessageText, [tfLeft, tfSingleLine]); + + CurrentY := CurrentY + MessageTextHeight + 2; + + Sender.Canvas.Font.Assign(IssueMetaLabel.Font); + IssueMetaText := GetIssueMetadataText(Issue); + MetaTextHeight := Sender.Canvas.TextHeight(IssueMetaText); + + MetaRect := Rect(TextStartX, CurrentY, + Item.DisplayRect(drBounds).Right - 4, CurrentY + MetaTextHeight); + Sender.Canvas.TextRect(MetaRect, IssueMetaText, [tfLeft, tfSingleLine]); + +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.IssueControlListContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); +var + Item: TListItem; + Popup: TPopupMenu; + Point: TPoint; +begin + Handled := False; + + Item := ListView.GetItemAt(MousePos.X, MousePos.Y); + if Assigned(Item) then + begin + Popup := CreateIssuePopup(Item.Index); + if Assigned(Popup) then begin + Point := ListView.ClientToScreen(MousePos); + Popup.Popup(Point.X, Point.Y); + Handled := True; + end; + end; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.ListViewSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean); +begin + if Selected then + RefreshRuleView; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.IssueControlListItemDblClick(Sender: TObject); +var + SelectedIssue: ILiveIssue; + Editor: IIDESourceEditor; +begin + SelectedIssue := GetSelectedIssue; + if not Assigned(SelectedIssue) then begin + Exit; + end; + + // Issue line has been removed + if SelectedIssue.StartLine = -1 then begin + Exit; + end; + + if TryGetCurrentSourceEditor(Editor) and (Editor.EditViewCount <> 0) then begin + Editor.EditViews[0].GoToPosition(SelectedIssue.StartLine, SelectedIssue.StartLineOffset); + Editor.EditViews[0].Paint; + end; +end; + +procedure TLintToolFrame.MarqueeTimerTimer(Sender: TObject); +begin + ProgBar.Position := ProgBar.Position + 1; + if ProgBar.Position >= ProgBar.Max then + ProgBar.Position := ProgBar.Min; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.RefreshActiveFile; +begin + ChangeActiveFile(FCurrentPath); +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.RefreshIssueView; +begin + FIssues.Clear; + + if FCurrentPath <> '' then begin + FIssues.AddRange(TWrapper.WrapArray(Analyzer.GetIssues(FCurrentPath))); + end; + + ListView.Selected := nil; + ListView.ItemIndex := -1; + ListView.Items.Count := FIssues.Count; + ListView.Repaint; + + RefreshRuleView; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.RuleBrowserBeforeNavigate2(Sender: TObject; const pDisp: IDispatch; + const URL, Flags, TargetFrameName, PostData, Headers: OleVariant; var Cancel: WordBool); +var + UrlStr: string; +begin + UrlStr := VarToStr(URL); + + Log.Debug('RuleBrowser navigating to: %s (NavigationAllowed: %s)', [UrlStr, BoolToStr(FNavigationAllowed, True)]); + + // Always allow navigation initiated by DelphiLint + if FNavigationAllowed then begin + Log.Debug('Navigation allowed by DelphiLint: %s', [UrlStr]); + // Reset flag after allowing navigation to prevent interference with subsequent navigations + FNavigationAllowed := False; + Cancel := False; + Exit; + end; + + // For navigations not controlled by DelphiLint: + // Allow navigation for: + // - Local files (file:///) + // - about: pages (about:blank, etc.) + if StartsText('file:', UrlStr) or StartsText('about:', UrlStr) then begin + Log.Debug('Allowing local/about navigation in RuleBrowser: %s', [UrlStr]); + Cancel := False; + end + else begin + // Open other URLs (http, https, etc.) in external browser + Log.Info('External URL requested in rule webview, opening externally: %s', [UrlStr]); + Cancel := True; + ShellExecute(0, 'open', PChar(UrlStr), nil, nil, SW_SHOWNORMAL); + end; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.RuleBrowserNewWindow2(Sender: TObject; var ppDisp: IDispatch; var Cancel: WordBool); +begin + Log.Info('New window requested in rule webview, intercepting and cancelling'); + Cancel := True; + ppDisp := nil; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.RuleBrowserDocumentComplete(Sender: TObject; const pDisp: IDispatch; const URL: OleVariant); +begin + Log.Debug('Rule browser document completed successfully for URL: %s', [VarToStr(URL)]); +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.RefreshRuleView; +var + SelectedIssue: ILiveIssue; + Rule: TRule; +begin + SelectedIssue := GetSelectedIssue; + + if Assigned(SelectedIssue) then begin + Rule := Analyzer.GetRule(SelectedIssue.RuleKey); + RulePanel.Visible := True; + SplitPanel.Visible := True; + if Assigned(Rule) then begin + SetRuleView(Rule); + end; + end + else begin + SplitPanel.Visible := False; + RulePanel.Visible := False; + end; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.SetLogMessages(LogMessages: TArray); +var + Log: string; + ErrorCount: Integer; + WarningCount: Integer; +begin + FLastAnalysisLogs := LogMessages; + FLastAnalysisTime := Now; + + ErrorCount := 0; + WarningCount := 0; + for Log in LogMessages do begin + if StartsStr('[ERROR]', Log) then begin + Inc(ErrorCount); + end + else if StartsStr('[WARN]', Log) then begin + Inc(WarningCount); + end; + end; + + if ErrorCount > 0 then begin + ErrorButton.Caption := Format('%d error%s', [ErrorCount, IfThen(ErrorCount = 1, '', 's')]); + end + else if WarningCount > 0 then begin + WarningButton.Caption := Format('%d warning%s', [WarningCount, IfThen(WarningCount = 1, '', 's')]); + end; + + ErrorButtonPanel.Visible := ErrorCount > 0; + WarningButtonPanel.Visible := (ErrorCount = 0) and (WarningCount > 0); + ViewLogItem.Enabled := Length(LogMessages) > 0; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFrame.SetRuleView(Rule: TRule); +var + HtmlFilePath: string; +begin + if (not FRuleHtmls.ContainsKey(Rule.RuleKey)) or (not FileExists(FRuleHtmls[Rule.RuleKey])) then begin + FRuleHtmls.AddOrSetValue(Rule.RuleKey, FRuleHtmlGenerator.GenerateHtmlFile(Rule)); + end; + + if FVisibleRule <> Rule.RuleKey then begin + HtmlFilePath := FRuleHtmls[Rule.RuleKey]; + Log.Debug('SetRuleView: Navigating to %s for rule %s', [HtmlFilePath, Rule.RuleKey]); + + // Set flag before navigation so it is respected in BeforeNavigate2 + FNavigationAllowed := True; + + try + RuleBrowser.Navigate('file:///' + NormalizePath(HtmlFilePath)); + except + on E: EOleException do begin + Log.Warn('OLE exception occurred during navigation: %s', [E.Message]); + FNavigationAllowed := False; // Reset flag on error + if E.Message <> 'Unspecified error' then begin + raise; + end; + end; + end; + FVisibleRule := Rule.RuleKey; + end; +end; + +//______________________________________________________________________________________________________________________ + +function TLintToolFormInfo.GetIdentifier: string; +begin + Result := 'DelphiLintToolForm'; +end; + +//______________________________________________________________________________________________________________________ + +procedure TLintToolFormInfo.FrameCreated(AFrame: TCustomFrame); +begin + LintContext.IDEServices.ApplyTheme(AFrame); +end; + +//______________________________________________________________________________________________________________________ + +function TLintToolFormInfo.GetCaption: string; +begin + Result := 'DelphiLint'; +end; + +//______________________________________________________________________________________________________________________ + +function TLintToolFormInfo.GetFrameClass: TCustomFrameClass; +begin + Result := TLintToolFrame; +end; + +end. diff --git a/client/source/DelphiLint.Utils.pas b/client/source/DelphiLint.Utils.pas index e25b2a7e..29014b9a 100644 --- a/client/source/DelphiLint.Utils.pas +++ b/client/source/DelphiLint.Utils.pas @@ -129,6 +129,9 @@ function GetDelphiVersion: string; else if ProductVersion = '20.0' then begin Result := 'VER330'; end + else if ProductVersion = '19.0' then begin + Result := 'VER320'; + end else begin Result := 'VER360'; end; diff --git a/client/source/DelphiLintClient250.dpk b/client/source/DelphiLintClient250.dpk new file mode 100644 index 00000000..1ffef5db --- /dev/null +++ b/client/source/DelphiLintClient250.dpk @@ -0,0 +1,73 @@ +package DelphiLintClient250; + +{$R *.res} +{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} +{$ALIGN 8} +{$ASSERTIONS ON} +{$BOOLEVAL OFF} +{$DEBUGINFO OFF} +{$EXTENDEDSYNTAX ON} +{$IMPORTEDDATA ON} +{$IOCHECKS ON} +{$LOCALSYMBOLS OFF} +{$LONGSTRINGS ON} +{$OPENSTRINGS ON} +{$OPTIMIZATION ON} +{$OVERFLOWCHECKS OFF} +{$RANGECHECKS OFF} +{$REFERENCEINFO OFF} +{$SAFEDIVIDE OFF} +{$STACKFRAMES OFF} +{$TYPEDADDRESS OFF} +{$VARSTRINGCHECKS ON} +{$WRITEABLECONST OFF} +{$MINENUMSIZE 1} +{$IMAGEBASE $400000} +{$DEFINE RELEASE} +{$DEFINE TOOLSAPI} +{$ENDIF IMPLICITBUILDING} +{$DESCRIPTION 'DelphiLint'} +{$DESIGNONLY} +{$IMPLICITBUILD ON} + +requires + rtl, + vcl, + vclie, + designide, + IndyProtocols, + dbrtl, + vcldb, + dsnap; + +contains + DelphiLint.Handlers in 'DelphiLint.Handlers.pas', + DelphiLint.Server in 'DelphiLint.Server.pas', + DelphiLint.Data in 'DelphiLint.Data.pas', + DelphiLint.FileLogger in 'DelphiLint.FileLogger.pas', + DelphiLint.IDEBaseTypes in 'DelphiLint.IDEBaseTypes.pas', + DelphiLint.Events in 'DelphiLint.Events.pas', + DelphiLint.Settings in 'DelphiLint.Settings.pas', + DelphiLint.ProjectOptions in 'DelphiLint.ProjectOptions.pas', + DelphiLint.Analyzer in 'DelphiLint.Analyzer.pas', + DelphiLint.Plugin in 'DelphiLint.Plugin.pas' {PluginCore: TDataModule}, + DelphiLint.Utils in 'DelphiLint.Utils.pas', + DelphiLint.SettingsFrame in 'DelphiLint.SettingsFrame.pas' {LintSettingsFrame: TFrame}, + DelphiLint.OptionsForm in 'DelphiLint.OptionsForm.pas' {LintOptionsForm}, + DelphiLint.Properties in 'DelphiLint.Properties.pas', + DelphiLint.SetupForm in 'DelphiLint.SetupForm.pas' {LintSetupForm}, + DelphiLint.Version in 'DelphiLint.Version.pas', + DelphiLint.Resources in 'DelphiLint.Resources.pas', + DelphiLint.Context in 'DelphiLint.Context.pas', + DelphiLint.IDEContext in 'DelphiLint.IDEContext.pas', + DelphiLint.HtmlGen in 'DelphiLint.HtmlGen.pas', + DelphiLint.LiveData in 'DelphiLint.LiveData.pas', + DelphiLint.IssueActions in 'DelphiLint.IssueActions.pas', + DelphiLint.PopupHook in 'DelphiLint.PopupHook.pas', + DelphiLint.ExternalConsts in 'DelphiLint.ExternalConsts.pas', + DelphiLint.LogViewer in 'DelphiLint.LogViewer.pas' {LogViewerForm}, + DelphiLint.ToolFrame.Legacy in 'DelphiLint.ToolFrame.Legacy.pas' {LintToolFrame: TFrame}; + +{$R *Additional.res} + +end. diff --git a/client/source/DelphiLintClient250.dproj b/client/source/DelphiLintClient250.dproj new file mode 100644 index 00000000..b96405b7 --- /dev/null +++ b/client/source/DelphiLintClient250.dproj @@ -0,0 +1,561 @@ + + + True + Package + Release + VCL + DelphiLintClient250.dpk + Win32 + {26783A2A-7221-40E7-AD37-9319A2677FB0} + 18.4 + 1 + + + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + DelphiLintClient250 + .\target\250\$(Config) + All + .\target\250\$(Config) + .\target\250\$(Config)\dcu + TOOLSAPI;$(DCC_Define) + .\250\$(Config) + true + true + true + + false + + FileVersion=1.0.0.0 + 2057 + + + Debug + DelphiLint + vcl;rtl;IndyProtocols;vclie;vcledge;dbrtl;vcldb;dsnap;$(DCC_UsePackage) + + + true + true + DEBUG;$(DCC_Define) + true + true + false + true + true + + + true + $(BDSBIN)\bds.exe + + + 0 + RELEASE;$(DCC_Define) + false + 0 + + + + MainSource + + + + + + + + + + + + + + + + + + + +
PluginCore
+ dfm + TDataModule +
+ + +
LintSettingsFrame
+ dfm + TFrame +
+ +
LintOptionsForm
+ dfm +
+ + +
LintSetupForm
+ dfm +
+ + + + + + + + + + +
LogViewerForm
+ dfm +
+ +
LintToolFrame
+ dfm + TFrame +
+ + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Package + + + + DelphiLintClient250.dpk + + + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + True + + + + + DelphiLintClient250.bpl + true + + + + + DelphiLintClient250.bpl + true + + + + + 1 + + + Contents\MacOS + 0 + + + + + classes + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + + + res\values + 1 + + + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + + + 1 + + + 1 + + + 0 + + + + + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + + + + 1 + + + 1 + + + 1 + + + + + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 0 + + + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + + + + + + + + + 12 + + + + + + pwsh -NoProfile -File PreBuild.ps1 $(PROJECTNAME) + False + + False + move /y dlversion.inc.orig dlversion.inc + True + + + pwsh -NoProfile -File PreBuild.ps1 $(PROJECTNAME) + False + + False + move /y dlversion.inc.orig dlversion.inc + True + +
diff --git a/client/test/DelphiLintClientTest250.dpr b/client/test/DelphiLintClientTest250.dpr new file mode 100644 index 00000000..d4647cfc --- /dev/null +++ b/client/test/DelphiLintClientTest250.dpr @@ -0,0 +1,95 @@ +program DelphiLintClientTest250; + +{$R *.res} + +{$IFDEF TESTGUI} +{$APPTYPE GUI} +{$ELSE} +{$APPTYPE CONSOLE} +{$ENDIF} +{$STRONGLINKTYPES ON} +uses + System.SysUtils, + {$IFDEF TESTINSIGHT} + TestInsight.DUnitX, + {$ELSE} + {$IFDEF TESTGUI} + DUnitX.Loggers.GUI.VCL, + {$ELSE} + DUnitX.Loggers.Console, + {$ENDIF } + {$ENDIF } + DUnitX.Loggers.XML.NUnit, + DUnitX.TestFramework, + DelphiLintTest.Events in 'DelphiLintTest.Events.pas', + DelphiLintTest.Data in 'DelphiLintTest.Data.pas', + DelphiLintTest.MockUtils in 'DelphiLintTest.MockUtils.pas', + DelphiLintTest.Handlers in 'DelphiLintTest.Handlers.pas', + DelphiLintTest.MockContext in 'DelphiLintTest.MockContext.pas', + DelphiLintTest.Plugin in 'DelphiLintTest.Plugin.pas', + DelphiLintTest.Utils in 'DelphiLintTest.Utils.pas', + DelphiLintTest.Server in 'DelphiLintTest.Server.pas', + DelphiLintTest.FileLogger in 'DelphiLintTest.FileLogger.pas', + DelphiLintTest.HtmlGen in 'DelphiLintTest.HtmlGen.pas', + DelphiLintTest.Settings in 'DelphiLintTest.Settings.pas', + DelphiLintTest.LiveData in 'DelphiLintTest.LiveData.pas', + DelphiLintTest.IssueActions in 'DelphiLintTest.IssueActions.pas', + DelphiLintTest.Properties in 'DelphiLintTest.Properties.pas'; + +{$R *Additional.res} + +{$IFDEF TESTINSIGHT} +begin + TestInsight.DUnitX.RunRegisteredTests; +{$ELSE} +{$IFDEF TESTGUI} +begin + DUnitX.Loggers.GUI.VCL.Run; +{$ELSE} +var + Runner: ITestRunner; + Results: IRunResults; + Logger: ITestLogger; + NUnitLogger : ITestLogger; +begin + //Check command line options, will exit if invalid + TDUnitX.CheckCommandLine; + try + //Create the test runner + Runner := TDUnitX.CreateRunner; + //Tell the runner to use RTTI to find Fixtures + Runner.UseRTTI := True; + //When true, Assertions must be made during tests; + Runner.FailsOnNoAsserts := True; + + //tell the runner how we will log things + //Log to the console window if desired + if TDUnitX.Options.ConsoleMode <> TDunitXConsoleMode.Off then + begin + Logger := TDUnitXConsoleLogger.Create(TDUnitX.Options.ConsoleMode = TDunitXConsoleMode.Quiet); + Runner.AddLogger(Logger); + end; + //Generate an NUnit compatible XML File + NUnitLogger := TDUnitXXMLNUnitFileLogger.Create(TDUnitX.Options.XMLOutputFile); + Runner.AddLogger(NUnitLogger); + + //Run tests + Results := Runner.Execute; + if not Results.AllPassed then + System.ExitCode := EXIT_ERRORS; + + {$IFNDEF CI} + //We don't want this happening when running under CI. + if TDUnitX.Options.ExitBehavior = TDUnitXExitBehavior.Pause then + begin + System.Write('Done.. press key to quit.'); + System.Readln; + end; + {$ENDIF} + except + on E: Exception do + System.Writeln(E.ClassName, ': ', E.Message); + end; +{$ENDIF} +{$ENDIF} +end. diff --git a/client/test/DelphiLintClientTest250.dproj b/client/test/DelphiLintClientTest250.dproj new file mode 100644 index 00000000..2321d46a --- /dev/null +++ b/client/test/DelphiLintClientTest250.dproj @@ -0,0 +1,226 @@ + + + True + Console + TestInsight + None + DelphiLintClientTest250.dpr + Win32 + {602BACA7-000B-4E3A-AD44-97865D89E115} + 18.4 + 1 + + + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Base + true + + + true + Cfg_3 + true + true + + + true + Cfg_3 + true + true + + + true + Cfg_4 + true + true + true + + + DelphiLintClientTest250 + .\target\250\$(Config) + .\target\250\$(Config)\dcu + .\target\250\$(Config) + 3 + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + $(DUnitX);..\source;$(BDS)\source\Indy10\Core;$(BDS)\source\Indy10\System;$(BDS)\source\Indy10\Protocols;$(DCC_UnitSearchPath) + $(BDS)\bin\delphi_PROJECTICNS.icns + $(BDS)\bin\delphi_PROJECTICON.ico + + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 2057 + TESTINSIGHT;$(DCC_Define) + + + none + Debug + true + true + true + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + false + true + true + dxPSdxSpreadSheetLnkRS28;vclwinx;fmx;vclie;DbxCommonDriver;bindengine;VCLRESTComponents;FireDACCommonODBC;cxGridEMFRS28;cxExportRS28;FireDACCommonDriver;dxPSPrVwRibbonRS28;appanalytics;IndyProtocols;vclx;dbxcds;vcledge;dxCloudServiceLibraryRS28;cxLibraryRS28;bindcompvclwinx;FmxTeeUI;dxGDIPlusRS28;bindcompfmx;dxCoreRS28;inetdb;dxSpreadSheetCoreRS28;dxPSCoreRS28;FireDACSqliteDriver;DbxClientDriver;dxSpreadSheetRS28;dxTabbedMDIRS28;Tee;soapmidas;dxBarRS28;vclactnband;TeeUI;dxWizardControlRS28;fmxFireDAC;dbexpress;dxADOServerModeRS28;Jcl;CEF4DelphiVCLRTL;DBXMySQLDriver;VclSmp;inet;sbridge280;dxServerModeRS28;dxPSdxLCLnkRS28;vcltouch;fmxase;cxTreeListRS28;dxBarDBNavRS28;dbrtl;dxPSLnksRS28;omDDControlsAlex;fmxdae;TeeDB;dxPScxCommonRS28;omUtilsAlex;FireDACMSAccDriver;AdRockSuiteAlex;CustomIPTransport;dxNavBarRS28;omIDEWizardsAlex;CEF4DelphiFMXRTL;dxSpreadSheetReportDesignerRS28;vcldsnap;dxComnRS28;DBXInterBaseDriver;IndySystem;dxSpreadSheetConditionalFormattingDialogsRS28;vcldb;dxDBXServerModeRS28;dxPSDBTeeChartRS28;dxmdsRS28;dxPsPrVwAdvRS28;dxRibbonRS28;VirtualTreesR;dxPScxExtCommonRS28;vclFireDAC;omWebComponentsAlex;bindcomp;FireDACCommon;dxPScxGridLnkRS28;IndyCore;RESTBackendComponents;dxRibbonCustomizationFormRS28;dxBarExtDBItemsRS28;bindcompdbx;cxTreeListdxBarPopupMenuRS28;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;RichViewActionsD11;DBXSqliteDriver;vcl;dsnapxml;adortl;dsnapcon;dxBarExtItemsRS28;dxPSTeeChartRS28;dxSpreadSheetCoreConditionalFormattingDialogsRS28;RVHunSpellPkgD11;cxGridRS28;vclimg;FireDACPgDriver;FireDAC;inetdbxpress;xmlrtl;tethering;bindcompvcl;dsnap;dxEMFRS28;CloudService;dxPScxTLLnkRS28;fmxobj;bindcompvclsmp;FMXTee;dxPScxPCProdRS28;RVPkgD11;soaprtl;Spring.Data;Markdown;soapserver;FireDACIBDriver;$(DCC_UsePackage) + (None) + 1033 + + + true + true + DEBUG;TESTGUI;$(DCC_Define) + true + true + false + true + true + $(BDS)\source\DunitX;$(DCC_UnitSearchPath) + + + false + 1033 + + + TESTINSIGHT;$(DCC_Define) + + + true + true + true + 1033 + + + DEBUG;$(DCC_Define) + + + 1033 + + + CI;$(DCC_Define) + + + 1033 + + + + MainSource + + + + + + + + + + + + + + + + + Base + + + Cfg_4 + Cfg_3 + + + Cfg_2 + Base + + + Cfg_1 + Base + + + Cfg_3 + Base + + + + Delphi.Personality.12 + Application + + + + DelphiLintClientTest250.dpr + + + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + True + + + 12 + + + + + + pwsh -NoProfile -File ..\BuildAdditionalResources.ps1 $(PROJECTNAME) + False + + False + + False + + + pwsh -NoProfile -File ..\BuildAdditionalResources.ps1 $(PROJECTNAME) + False + + False + + False + + + pwsh -NoProfile -File ..\BuildAdditionalResources.ps1 $(PROJECTNAME) + False + + False + + False + + + pwsh -NoProfile -File ..\BuildAdditionalResources.ps1 $(PROJECTNAME) + False + + False + + False + + diff --git a/client/test/DelphiLintTest.FileLogger.pas b/client/test/DelphiLintTest.FileLogger.pas index df84f19f..99b51bb8 100644 --- a/client/test/DelphiLintTest.FileLogger.pas +++ b/client/test/DelphiLintTest.FileLogger.pas @@ -76,7 +76,7 @@ function TFileLoggerTest.BuildLogger: ILogger; function TFileLoggerTest.GetLog: TArray; begin - Result := TFile.ReadAllLines(FLogPath); + Result := TArray(TFile.ReadAllLines(FLogPath)); end; //______________________________________________________________________________________________________________________ diff --git a/client/test/DelphiLintTest.HtmlGen.pas b/client/test/DelphiLintTest.HtmlGen.pas index d2316094..59436de6 100644 --- a/client/test/DelphiLintTest.HtmlGen.pas +++ b/client/test/DelphiLintTest.HtmlGen.pas @@ -234,7 +234,8 @@ procedure TRuleHtmlGeneratorTest.TestLinksToJsLibScript; ); try HtmlText := FHtmlGenerator.GenerateHtmlText(Rule); - Assert.Contains(HtmlText, ''); + Assert.Contains(HtmlText, ''); finally FreeAndNil(Rule); end; @@ -340,7 +341,12 @@ procedure TRuleHtmlGeneratorTest.TestCleanCodeRuleContainsAttributes; var Rule: TRule; HtmlText: string; + Dict: TDictionary; begin + Dict := TDictionary.Create; + Dict.AddOrSetValue(sqaSecurity, imsMedium); + Dict.AddOrSetValue(sqaMaintainability, imsLow); + Rule := TRule.Create( 'rk1', 'This rule could be better', @@ -350,10 +356,7 @@ procedure TRuleHtmlGeneratorTest.TestCleanCodeRuleContainsAttributes; TRuleCleanCode.Create( ccaClear, cccIntentional, - TDictionary.Create([ - TPair.Create(sqaSecurity, imsMedium), - TPair.Create(sqaMaintainability, imsLow) - ]) + Dict ) ); try @@ -370,7 +373,12 @@ procedure TRuleHtmlGeneratorTest.TestCleanCodeRuleDoesNotContainRuleTypeOrSeveri var Rule: TRule; HtmlText: string; + Dict: TDictionary; begin + Dict := TDictionary.Create; + Dict.AddOrSetValue(sqaSecurity, imsMedium); + Dict.AddOrSetValue(sqaMaintainability, imsLow); + Rule := TRule.Create( 'rk1', 'This rule could be better', @@ -380,10 +388,7 @@ procedure TRuleHtmlGeneratorTest.TestCleanCodeRuleDoesNotContainRuleTypeOrSeveri TRuleCleanCode.Create( ccaClear, cccIntentional, - TDictionary.Create([ - TPair.Create(sqaSecurity, imsMedium), - TPair.Create(sqaMaintainability, imsLow) - ]) + Dict ) ); try diff --git a/client/test/DelphiLintTest.LiveData.pas b/client/test/DelphiLintTest.LiveData.pas index ff580ce9..977ca3ed 100644 --- a/client/test/DelphiLintTest.LiveData.pas +++ b/client/test/DelphiLintTest.LiveData.pas @@ -382,7 +382,7 @@ procedure TLiveDataTest.TestWrongNumberOfAssociatedLinesRaisesRangeError; try Assert.WillRaise( procedure begin - FreeAndNil(TLiveIssueImpl.Create(IssueData, ['abc', 'def'], False)); + TLiveIssueImpl.Create(IssueData, ['abc', 'def'], False).Free; end ); finally diff --git a/client/test/DelphiLintTest.MockContext.pas b/client/test/DelphiLintTest.MockContext.pas index a1fdd878..fab994a7 100644 --- a/client/test/DelphiLintTest.MockContext.pas +++ b/client/test/DelphiLintTest.MockContext.pas @@ -576,11 +576,13 @@ procedure TMockAnalyzer.MockFileHistory(Path: string; History: TFileAnalysisHist //______________________________________________________________________________________________________________________ procedure TMockAnalyzer.MockFileIssue(Path: string; Line: Integer; Issue: ILiveIssue); +var + Dict: TDictionary; begin Path := NormalizePath(Path); - FIssues.AddOrSetValue( - Path, - TDictionary.Create([TPair.Create(Line, Issue)])); + Dict := TDictionary.Create(); + Dict.AddOrSetValue(Line, Issue); + FIssues.AddOrSetValue(Path, Dict); end; //______________________________________________________________________________________________________________________ diff --git a/client/test/DelphiLintTest.Server.pas b/client/test/DelphiLintTest.Server.pas index 9d17e9af..2bb3c797 100644 --- a/client/test/DelphiLintTest.Server.pas +++ b/client/test/DelphiLintTest.Server.pas @@ -153,8 +153,13 @@ procedure TServerTcpConnectionTest.TestSendPing; Assert.AreEqual(wrSignaled, Event.WaitFor(1000), FailReason); Assert.AreEqual(CPing, Integer(ReceivedCategory)); Assert.AreEqual(95, ReceivedId); +{$IF CompilerVersion < 33.0} + Assert.AreEqual(9, ReceivedLength); + Assert.AreEqual('ab£c def', ReceivedDecodedStr); +{$ELSE} Assert.AreEqual(11, ReceivedLength); Assert.AreEqual('"ab£c def"', ReceivedDecodedStr); +{$ENDIF} finally FreeAndNil(Msg); FreeAndNil(Connection); diff --git a/server/delphilint-server/src/main/java/au/com/integradev/delphilint/analysis/AnalysisOrchestrator.java b/server/delphilint-server/src/main/java/au/com/integradev/delphilint/analysis/AnalysisOrchestrator.java index 578150a6..17e4cd2f 100644 --- a/server/delphilint-server/src/main/java/au/com/integradev/delphilint/analysis/AnalysisOrchestrator.java +++ b/server/delphilint-server/src/main/java/au/com/integradev/delphilint/analysis/AnalysisOrchestrator.java @@ -107,8 +107,8 @@ private static AnalysisConfiguration buildConfiguration( } private static Charset getConfiguredCharset(Map properties) { - if (properties.containsKey("sonar.encoding")) { - return Charset.forName(properties.get("sonar.encoding")); + if (properties.containsKey("sonar.sourceEncoding")) { + return Charset.forName(properties.get("sonar.sourceEncoding")); } else { return Charset.defaultCharset(); }