From 8ae1d62bbe20bbe44ed89c23c682b0b3aa1eaafa Mon Sep 17 00:00:00 2001 From: paul Date: Mon, 8 Sep 2008 03:41:32 +0000 Subject: [PATCH] lcl: - add more UTF8 string functions (Delete, Insert, LoweCase, UpperCase) - revert gtk SelStart, SelLength changes - they are and will return position in Characters - fix combobox completion code git-svn-id: trunk@16478 - --- lcl/include/customcombobox.inc | 22 ++++----- lcl/interfaces/gtk2/gtk2wsstdctrls.pp | 48 ++++--------------- lcl/lclproc.pas | 68 ++++++++++++++++++++++----- 3 files changed, 78 insertions(+), 60 deletions(-) diff --git a/lcl/include/customcombobox.inc b/lcl/include/customcombobox.inc index d87e204ac1..b0bf3a5719 100644 --- a/lcl/include/customcombobox.inc +++ b/lcl/include/customcombobox.inc @@ -483,7 +483,7 @@ end; procedure TCustomComboBox.KeyUp(var Key: Word; Shift: TShiftState); var - iSelStart: Integer; // byte position + iSelStart: Integer; // char position sCompleteText, sPrefixText, sResultText: string; begin inherited KeyUp(Key, Shift); @@ -510,10 +510,10 @@ begin iSelStart := SelStart;//Capture original cursor position //DebugLn(['TCustomComboBox.UTF8KeyPress SelStart=',SelStart,' Text=',Text]); //End of line completion - if ((iSelStart < Length(Text)) - and (cbactEndOfLineComplete in FAutoCompleteText)) then + if ((iSelStart < UTF8Length(Text)) and + (cbactEndOfLineComplete in FAutoCompleteText)) then Exit; - sPrefixText := LeftStr(Text, iSelStart); + sPrefixText := UTF8Copy(Text, 1, iSelStart); sCompleteText := GetCompleteText(Text, iSelStart, (cbactSearchCaseSensitive in FAutoCompleteText), (cbactSearchAscending in FAutoCompleteText), Items); @@ -524,12 +524,12 @@ begin if ((cbactEndOfLineComplete in FAutoCompleteText) and (cbactRetainPrefixCase in FAutoCompleteText)) then begin//Retain Prefix Character cases - Delete(sResultText, 1, iSelStart); - Insert(sPrefixText, sResultText, 1); + UTF8Delete(sResultText, 1, iSelStart); + UTF8Insert(sPrefixText, sResultText, 1); end; Text := sResultText; SelStart := iSelStart; - SelLength := Length(Text); + SelLength := UTF8Length(Text); end; end; end; @@ -539,8 +539,8 @@ procedure TCustomComboBox.KeyPress(var Key: char); begin //Convert character cases if FCharCase is not ecNormalCase case FCharCase of - ecLowerCase: Key := lowerCase(Key); - ecUpperCase: Key := upCase(Key); + ecLowerCase: Key := lowerCase(Key); + ecUpperCase: Key := upCase(Key); end; inherited KeyPress(Key); end; @@ -549,8 +549,8 @@ procedure TCustomComboBox.UTF8KeyPress(var UTF8Key: TUTF8Char); begin //Convert character cases if FCharCase is not ecNormalCase case FCharCase of - ecLowerCase: UTF8Key := AnsiLowerCase(UTF8Key); - ecUpperCase: UTF8Key := AnsiUpperCase(UTF8Key); + ecLowerCase: UTF8Key := AnsiLowerCase(UTF8Key); + ecUpperCase: UTF8Key := AnsiUpperCase(UTF8Key); end; inherited UTF8KeyPress(UTF8Key); end; diff --git a/lcl/interfaces/gtk2/gtk2wsstdctrls.pp b/lcl/interfaces/gtk2/gtk2wsstdctrls.pp index b1a88ae0fe..47ca762199 100644 --- a/lcl/interfaces/gtk2/gtk2wsstdctrls.pp +++ b/lcl/interfaces/gtk2/gtk2wsstdctrls.pp @@ -1224,14 +1224,10 @@ begin // if the combo is an editable ... Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); if Entry<>nil then begin - // Note: gtk begins at 0, LCL at 1 - if gtk_editable_get_selection_bounds(PGtkEditable(Entry), @AStart, @AEnd) = gtk_true then - Result := Min(AStart,AEnd) + if gtk_editable_get_selection_bounds(PGtkEditable(Entry), @AStart, @AEnd) = False then + Result := gtk_editable_get_position(PGtkEditable(Entry)) else - Result := gtk_editable_get_position(PGtkEditable(Entry)); - //DebugLn(['TGtk2WSCustomComboBox.GetSelStart CharStart=',Result]); - Result:=UTF8CharToByteIndex(gtk_entry_get_text(Entry),High(integer),Result+1)-1; - //DebugLn(['TGtk2WSCustomComboBox.GetSelStart ',dbgsName(ACustomComboBox),' AText=',gtk_entry_get_text(Entry),' Result=',Result]); + Result := Min(AStart, AEnd); end; end; @@ -1241,7 +1237,6 @@ var WidgetInfo: PWidgetInfo; Entry: PGtkEntry; AStart, AEnd: gint; - AText: Pgchar; begin Result := 0; WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle)); @@ -1249,16 +1244,9 @@ begin // if the combo is an editable ... Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); if Entry<>nil then begin - if gtk_editable_get_selection_bounds(PGtkEditable(Entry), @AStart, @AEnd) = gtk_true then - begin - MakeMinMax(AStart,AEnd); - AText:=gtk_editable_get_chars(PGtkEditable(Entry),AStart,AEnd); - Result:=UTF8Length(AText,(AEnd-AStart)*4); - g_free(AText); - end - else - Result := 0; - DebugLn(['TGtk2WSCustomComboBox.GetSelLength ',dbgsName(ACustomComboBox),' AText=',gtk_entry_get_text(Entry),' Result=',Result]); + if gtk_editable_get_selection_bounds(PGtkEditable(Entry), @AStart, @AEnd) = False then + Exit(gtk_editable_get_position(PGtkEditable(Entry))); + Result := ABS(AStart - AEnd); end; end; @@ -1325,16 +1313,13 @@ class procedure TGtk2WSCustomComboBox.SetSelStart( var WidgetInfo: PWidgetInfo; Entry: PGtkEntry; - AText: Pgchar; begin WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle)); Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); if Entry<>nil then begin //gtk_entry_select_region(Entry, NewStart, NewStart); - AText:=gtk_entry_get_text(Entry); - //DebugLn(['TGtk2WSCustomComboBox.SetSelStart ',dbgsName(ACustomComboBox),' AText=',AText,' NewStart=',NewStart,' UTF8Start=',UTF8Length(AText,NewStart-1)]); - gtk_editable_set_position(PGtkEditable(Entry), UTF8Length(AText,NewStart)); + gtk_editable_set_position(PGtkEditable(Entry), NewStart); end; end; @@ -1343,27 +1328,14 @@ class procedure TGtk2WSCustomComboBox.SetSelLength( var WidgetInfo: PWidgetInfo; Entry: PGtkEntry; - AStart, AEnd: gint;// starts at 0 - ByteStart: LongInt;// starts at 0 - AText: Pgchar; - NewCharLength: LongInt; + Start: Integer; begin WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle)); Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); if Entry<>nil then begin - if gtk_editable_get_selection_bounds(PGtkEditable(Entry), @AStart, @AEnd) = gtk_true then - MakeMinMax(AStart,AEnd) - else - AStart := gtk_editable_get_position(PGtkEditable(Entry)); - AText:=gtk_entry_get_text(Entry); - NewCharLength:=NewLength; - if (NewCharLength>0) and (AText<>nil) then begin - ByteStart:=UTF8CharToByteIndex(AText,High(integer),AStart+1)-1; - NewCharLength:=UTF8Length(@AText[ByteStart],NewLength); - end; - //DebugLn(['TGtk2WSCustomComboBox.SetSelLength ',dbgsName(ACustomComboBox),' AText=',AText,' CharStart=',AStart,' ByteStart=',ByteStart,' NewLength=',NewLength,' NewCharLength=',NewCharLength]); - gtk_editable_select_region(PGtkEditable(Entry), AStart, AStart + NewCharLength); + Start := GetSelStart(ACustomComboBox); + gtk_editable_select_region(PGtkEditable(Entry), Start, Start + NewLength); end; end; diff --git a/lcl/lclproc.pas b/lcl/lclproc.pas index 451d6db6a7..c905da3334 100644 --- a/lcl/lclproc.pas +++ b/lcl/lclproc.pas @@ -302,6 +302,10 @@ function UTF8CharacterStrictLength(P: PChar): integer; function UTF8CStringToUTF8String(SourceStart: PChar; SourceLen: SizeInt) : string; function UTF8Pos(const SearchForText, SearchInText: string): integer; function UTF8Copy(const s: string; StartCharIndex, CharCount: integer): string; +procedure UTF8Delete(var s: String; StartCharIndex, CharCount: integer); +procedure UTF8Insert(const source: String; var s: string; StartCharIndex: integer); +function UTF8LowerCase(const s: String): String; +function UTF8UpperCase(const s: String): String; function FindInvalidUTF8Character(p: PChar; Count: integer; StopOnNonASCII: Boolean = false): integer; procedure AssignUTF8ListToAnsi(UTF8List, AnsiList: TStrings); @@ -533,11 +537,13 @@ function GetCompleteText(sText: string; iSelStart: Integer; function IsSamePrefix(sCompareText, sPrefix: string; iStart: Integer; var ResultText: string): Boolean; - var sTempText: string; + var + sTempText: string; begin Result := False; - sTempText := LeftStr(sCompareText, iStart); - if not bCaseSensitive then sTempText := UpperCase(sTempText); + sTempText := UTF8Copy(sCompareText, 1, iStart); + if not bCaseSensitive then + sTempText := UTF8UpperCase(sTempText); if (sTempText = sPrefix) then begin ResultText := sCompareText; @@ -545,25 +551,28 @@ function GetCompleteText(sText: string; iSelStart: Integer; end; end; -var i: Integer; - sPrefixText: string; +var + i: Integer; + sPrefixText: string; begin //DebugLn(['GetCompleteText sText=',sText,' iSelStart=',iSelStart,' bCaseSensitive=',bCaseSensitive,' bSearchAscending=',bSearchAscending,' slTextList.Count=',slTextList.Count]); Result := sText;//Default to return original text if no identical text are found if (sText = '') then Exit;//Everything is compatible with nothing, Exit. if (iSelStart = 0) then Exit;//Cursor at beginning if (slTextList.Count = 0) then Exit;//No text list to search for idtenticals, Exit. - sPrefixText := LeftStr(sText, iSelStart);//Get text from beginning to cursor position. + sPrefixText := UTF8Copy(sText, 1, iSelStart);//Get text from beginning to cursor position. if not bCaseSensitive then - sPrefixText := UpperCase(sPrefixText); + sPrefixText := UTF8UpperCase(sPrefixText); if bSearchAscending then begin - for i:=0 to slTextList.Count-1 do - if IsSamePrefix(slTextList[i], sPrefixText, iSelStart, Result) then Break; + for i := 0 to slTextList.Count - 1 do + if IsSamePrefix(slTextList[i], sPrefixText, iSelStart, Result) then + break; end else begin - for i:=slTextList.Count-1 downto 0 do - if IsSamePrefix(slTextList[i], sPrefixText, iSelStart, Result) then Break; + for i := slTextList.Count - 1 downto 0 do + if IsSamePrefix(slTextList[i], sPrefixText, iSelStart, Result) then + break; end; end; @@ -2684,6 +2693,43 @@ begin end; end; +procedure UTF8Delete(var s: String; StartCharIndex, CharCount: integer); +var + StartBytePos: PChar; + EndBytePos: PChar; + MaxBytes: PtrInt; +begin + StartBytePos:=UTF8CharStart(PChar(s),length(s),StartCharIndex-1); + if StartBytePos <> nil then + begin + MaxBytes:=PtrInt(PChar(s)+length(s)-StartBytePos); + EndBytePos:=UTF8CharStart(StartBytePos,MaxBytes,CharCount); + if EndBytePos=nil then + Delete(s,StartBytePos-PChar(s)+1,MaxBytes) + else + Delete(s,StartBytePos-PChar(s)+1,EndBytePos-StartBytePos); + end; +end; + +procedure UTF8Insert(const source: String; var s: string; StartCharIndex: integer); +var + StartBytePos: PChar; +begin + StartBytePos:=UTF8CharStart(PChar(s),length(s),StartCharIndex-1); + if StartBytePos <> nil then + Insert(source, s, StartBytePos-PChar(s)+1); +end; + +function UTF8LowerCase(const s: String): String; +begin + Result := UTF8Encode(WideLowerCase(UTF8Decode(s))); +end; + +function UTF8UpperCase(const s: String): String; +begin + Result := UTF8Encode(WideUpperCase(UTF8Decode(s))); +end; + function FindInvalidUTF8Character(p: PChar; Count: integer; StopOnNonASCII: Boolean): integer; // return -1 if ok