{******************************************************************

                       JEDI-VCL Demo

 Copyright (C) 2002 Project JEDI

 Original author:

 Contributor(s):

 You may retrieve the latest version of this file at the JEDI-JVCL
 home page, located at http://jvcl.delphi-jedi.org

 The contents of this file are used with permission, subject to
 the Mozilla Public License Version 1.1 (the "License"); you may
 not use this file except in compliance with the License. You may
 obtain a copy of the License at
 http://www.mozilla.org/MPL/MPL-1_1Final.html

 Software distributed under the License is distributed on an
 "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 implied. See the License for the specific language governing
 rights and limitations under the License.

******************************************************************}

unit JvCharStrEditor;

{$I jvcl.inc}

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, ComCtrls, Menus, ActnList, ImgList;

type
  TfrmJvCharEditDlg = class(TForm)
    Panel1: TPanel;
    btnOK: TButton;
    btnCancel: TButton;
    lvCharacters: TListView;
    PopupMenu1: TPopupMenu;
    SelectAll1: TMenuItem;
    UnselectAll1: TMenuItem;
    Invertselection1: TMenuItem;
    ActionList1: TActionList;
    acCheckAll: TAction;
    acUnCheckAll: TAction;
    acInvertCheck: TAction;
    acAlpha: TAction;
    acAlphaNum: TAction;
    acHex: TAction;
    acFloat: TAction;
    acScientific: TAction;
    acCurrency: TAction;
    acInteger: TAction;
    Special1: TMenuItem;
    Alpha1: TMenuItem;
    acAlphaNum1: TMenuItem;
    acInteger1: TMenuItem;
    acFloat1: TMenuItem;
    acHex1: TMenuItem;
    acScientific1: TMenuItem;
    acCurrency1: TMenuItem;
    acLarge: TAction;
    acSmall: TAction;
    acList: TAction;
    acReport: TAction;
    View1: TMenuItem;
    Large1: TMenuItem;
    Small1: TMenuItem;
    List1: TMenuItem;
    Report1: TMenuItem;
    ImageList1: TImageList;
    acCheckSel: TAction;
    acUnCheckSel: TAction;
    CheckSelected1: TMenuItem;
    UnCheckSelected1: TMenuItem;
    N2: TMenuItem;
    N3: TMenuItem;
    N4: TMenuItem;
    cbFonts: TComboBox;
    procedure FormCreate(Sender: TObject);
    procedure lvCharactersInfoTip(Sender: TObject; Item: TListItem;
      var InfoTip: string);
    procedure acInvertCheckExecute(Sender: TObject);
    procedure acUnCheckAllExecute(Sender: TObject);
    procedure acCheckAllExecute(Sender: TObject);
    procedure acAlphaExecute(Sender: TObject);
    procedure acAlphaNumExecute(Sender: TObject);
    procedure acHexExecute(Sender: TObject);
    procedure acFloatExecute(Sender: TObject);
    procedure acScientificExecute(Sender: TObject);
    procedure acCurrencyExecute(Sender: TObject);
    procedure acIntegerExecute(Sender: TObject);
    procedure acLargeExecute(Sender: TObject);
    procedure acSmallExecute(Sender: TObject);
    procedure acListExecute(Sender: TObject);
    procedure acReportExecute(Sender: TObject);
    procedure lvCharactersResize(Sender: TObject);
    procedure acCheckSelExecute(Sender: TObject);
    procedure acUnCheckSelExecute(Sender: TObject);
    procedure lvCharactersEnter(Sender: TObject);
    procedure cbFontsCloseUp(Sender: TObject);
    procedure cbFontsKeyPress(Sender: TObject; var Key: Char);
    procedure lvCharactersAdvancedCustomDrawItem(Sender: TCustomListView;
      Item: TListItem; State: TCustomDrawState; Stage: TCustomDrawStage;
      var DefaultDraw: Boolean);
    procedure lvCharactersSelectItem(Sender: TObject; Item: TListItem;
      Selected: Boolean);
  private
    function getCharacters: string;
    procedure setCharacters(const Value: string);
    procedure UnCheckAll;
    { Private declarations }
  public
    { Public declarations }
    class function Edit(var Characters: string): boolean;
    property Characters: string read getCharacters write setCharacters;
  end;

  
const
  cAsciiNames:array [char] of PChar =
  (
  'NUL', // null
  'SOH', // start of heading
  'STX', // start of text
  'ETX', // end of text
  'EOT', // end of transmission
  'ENQ', // enquiry
  'ACK', // acknowledge
  'BEL', // bell
  'BS',  // backspace
  'TAB', // horizontal tab
  'LF',  // line feed
  'VT',  // vertical tab
  'FF',  // form feed
  'CR',  // carriage return
  'SO',  // shift out
  'SI',  // shift in
  'DLE', // data link escape
  'DC1', // device control 1
  'DC2', // device control 2
  'DC3', // device control 3
  'DC4', // device control 4
  'NAK', // negative acknowledge
  'SYN', // synch idle
  'ETB', // end of trans. block
  'CAN', // cancel
  'EM',  // end of medium
  'SUB', // substitute
  'ESC', // escape
  'FS',  // file separator
  'GS',  // group separator
  'RS',  // record separator
  'US',  // unit separator
  'SPACE', // space
                  #33, #34, #35, #36, #37, #38, #39,
   #40, #41, #42, #43, #44, #45, #46, #47, #48, #49,
   #50, #51, #52, #53, #54, #55, #56, #57, #58, #59,
   #60, #61, #62, #63, #64, #65, #66, #67, #68, #69,
   #70, #71, #72, #73, #74, #75, #76, #77, #78, #79,
   #80, #81, #82, #83, #84, #85, #86, #87, #88, #89,
   #90, #91, #92, #93, #94, #95, #96, #97, #98, #99,
  #100,#101,#102,#103,#104,#105,#106,#107,#108,#109,
  #110,#111,#112,#113,#114,#115,#116,#117,#118,#119,
  #120,#121,#122,#123,#124,#125,#126,#127,#128,#129,
  #130,#131,#132,#133,#134,#135,#136,#137,#138,#139,
  #140,#141,#142,#143,#144,#145,#146,#147,#148,#149,
  #150,#151,#152,#153,#154,#155,#156,#157,#158,#159,
  #160,#161,#162,#163,#164,#165,#166,#167,#168,#169,
  #170,#171,#172,#173,#174,#175,#176,#177,#178,#179,
  #180,#181,#182,#183,#184,#185,#186,#187,#188,#189,
  #190,#191,#192,#193,#194,#195,#196,#197,#198,#199,
  #200,#201,#202,#203,#204,#205,#206,#207,#208,#209,
  #210,#211,#212,#213,#214,#215,#216,#217,#218,#219,
  #220,#221,#222,#223,#224,#225,#226,#227,#228,#229,
  #230,#231,#232,#233,#234,#235,#236,#237,#238,#239,
  #240,#241,#242,#243,#244,#245,#246,#247,#248,#249,
  #250,#251,#252,#253,#254,#255);
  
// converts a syschar set to it's textual display representation
// as is displayed in the OI, f ex
// NOTE: this is *not* the opposite of StringToSysCharSet below!
function SysCharSetToString(ASet:TSysCharSet;Brackets:boolean):string;
// converts a string to a SysCharSet
function StringToSysCharSet(const S:string):TSysCharSet;
// returns either an unquoted name, like NUL, or a quoted character, like 'A'
function GetCharName(const Ch:char):string;

resourcestring
  SFormCaption = 'TJvFormatEdit.Characters Editor ($%.2x, #%.2u, "%s")';

implementation

{$R *.DFM}

function StringToSysCharSet(const S:string):TSysCharSet;
var i:integer;
begin
  Result := [];
  for i := 1 to Length(S) do
  begin
    Include(Result,S[i]);
    if Result = [#0..#255] then Exit; // everything included, so no need to continue
  end;
end;

function GetCharName(const Ch:char):string;
var FTmpType:word;
begin
  Result := cAsciiNames[Ch];
  GetStringTypeEx(LOCALE_USER_DEFAULT,CT_CTYPE1,@Ch,1,FTmpType);
  if (FTmpType and C1_CNTRL = 0) and (Ch <> #32) then
    Result := #39 + Result + #39;
end;

// far from perfect, but kind of works...
function SysCharSetToString(ASet:TSysCharSet;Brackets:boolean):string;
var i,LastChar,PrevChar:char;
begin
  PrevChar := #255;
  LastChar := #0;
  for i := #0 to #255 do
  begin
    if i in ASet then
    begin
//      if PrevChar = #0 then
      if Ord(i)-Ord(PrevChar) <> 1 then
      begin
        if Result <> '' then
          Result := Result + ',' + getCharName(i)
        else
          Result := getCharName(i);
        LastChar := i;
      end
      else if i = #255 then
      begin
        if Result = '' then
          Result := GetCharName(i)
        else if Ord(i) - Ord(LastChar) > 1 then
          Result := Result + '...' + GetCharName(i)
        else
          Result := Result + ',' + GetCharName(i);
        Break;
      end;
      PrevChar := i;
    end
    else
    begin
      if Ord(i) - Ord(LastChar) > 1 then
        Result := Result + '...' + GetCharName(Pred(i))
      else if (LastChar = #0) and (Pred(i) <> LastChar) and (i <> #0) then
        Result := Result + ',' + GetCharName(Pred(i));
      PrevChar := #255;
      LastChar := i;
    end;
  end;
  if (Length(Result) > 0) and (AnsiLastChar(Result) = ',') then
    SetLength(Result,Length(Result)-1);
  if Brackets then
    Result := '[' + Result + ']';
end;

{ TfrmJvCharEditDlg }

class function TfrmJvCharEditDlg.Edit(
  var Characters: string): boolean;
var
  frmJvCharEditDlg: TfrmJvCharEditDlg;
begin
  frmJvCharEditDlg := self.Create(Application);
  try
    frmJvCharEditDlg.Characters := Characters;
    Result := frmJvCharEditDlg.ShowModal = mrOK;
    if Result then
      Characters := frmJvCharEditDlg.Characters;
  finally
    frmJvCharEditDlg.Free;
  end;
end;

function TfrmJvCharEditDlg.getCharacters: string;
var i: integer;
begin
  Result := '';
  with lvCharacters do
    for i := 0 to Items.Count - 1 do
      if Items[i].Checked then
        Result := Result + Char(Items[i].Data);
end;

procedure TfrmJvCharEditDlg.setCharacters(const Value: string);
var i: integer;
begin
  acUnCheckAll.Execute;
  with lvCharacters do
    for i := 1 to Length(Value) do
      Items[Ord(Value[i])].Checked := true;
end;

procedure TfrmJvCharEditDlg.FormCreate(Sender: TObject);
var i: char;j:integer;
begin
  with lvCharacters do
  begin
    Items.BeginUpdate;
    try
      Items.Clear;
      for i := #0 to #255 do
        with Items.Add do
        begin
          Caption := Format('%s', [cAsciiNames[i]]);
          Data := Pointer(i);
        end;
    finally
      Items.EndUpdate;
    end;
  end;
  cbFonts.Items := Screen.Fonts;
  j := cbFonts.Items.IndexOf(Font.Name);
  if j = -1 then
    cbFonts.ItemIndex := cbFonts.Items.Add(Font.Name)
  else
    cbFonts.ItemIndex := j;
  Caption := Format(SFormCaption,[0,0,cAsciiNames[#0]]);
end;

procedure TfrmJvCharEditDlg.lvCharactersInfoTip(Sender: TObject;
  Item: TListItem; var InfoTip: string);
begin
  if Item <> nil then
    InfoTip := Format('$%.2x, #%.2d, "%s"', [integer(Item.Data), integer(Item.Data),cAsciiNames[Char(Item.Data)]]);
end;

procedure TfrmJvCharEditDlg.acInvertCheckExecute(Sender: TObject);
var i: integer;
begin
  with lvCharacters do
    for i := 0 to Items.Count - 1 do
      Items[i].Checked := not Items[i].Checked;
end;

procedure TfrmJvCharEditDlg.acUnCheckAllExecute(Sender: TObject);
var i: integer;
begin
  with lvCharacters do
    for i := 0 to Items.Count - 1 do
      Items[i].Checked := false;
end;

procedure TfrmJvCharEditDlg.acCheckAllExecute(Sender: TObject);
var i: integer;
begin
  with lvCharacters do
    for i := 0 to Items.Count - 1 do
      Items[i].Checked := true;
end;

procedure TfrmJvCharEditDlg.acAlphaExecute(Sender: TObject);
var i: integer;
begin
  with lvCharacters do
    for i := 0 to Items.Count - 1 do
      Items[i].Checked := IsCharAlpha(char(Items[i].Data));
end;

procedure TfrmJvCharEditDlg.acAlphaNumExecute(Sender: TObject);
var i: integer;
begin
  with lvCharacters do
    for i := 0 to Items.Count - 1 do
      Items[i].Checked := IsCharAlphaNumeric(char(Items[i].Data));
end;

procedure TfrmJvCharEditDlg.acHexExecute(Sender: TObject);
var i: integer;
begin
  with lvCharacters do
    for i := 0 to Items.Count - 1 do
      Items[i].Checked := char(Items[i].Data) in ['0'..'9', 'A'..'F', 'a'..'f'];
end;

procedure TfrmJvCharEditDlg.acFloatExecute(Sender: TObject);
var i: integer;
begin
  with lvCharacters do
    for i := 0 to Items.Count - 1 do
      Items[i].Checked := (char(Items[i].Data) in ['0'..'9', '-','+', DecimalSeparator]);
end;

procedure TfrmJvCharEditDlg.acScientificExecute(Sender: TObject);
var i: integer;
begin
  with lvCharacters do
    for i := 0 to Items.Count - 1 do
      Items[i].Checked := (char(Items[i].Data) in ['0'..'9', 'E','e','-','+', DecimalSeparator]);
end;

procedure TfrmJvCharEditDlg.acCurrencyExecute(Sender: TObject);
begin
  acFloat.Execute;
end;

procedure TfrmJvCharEditDlg.acIntegerExecute(Sender: TObject);
var i: integer;
begin
  with lvCharacters do
    for i := 0 to Items.Count - 1 do
      Items[i].Checked := (char(Items[i].Data) in ['0'..'9', '-','+']);
end;

procedure TfrmJvCharEditDlg.UnCheckAll;
begin
  acLarge.Checked := false;
  acSmall.Checked := false;
  acList.Checked := false;
  acReport.Checked := false;
end;

procedure TfrmJvCharEditDlg.acLargeExecute(Sender: TObject);
begin
  UnCheckAll;
  acLarge.Checked := true;
  lvCharacters.ViewStyle := vsIcon;
end;

procedure TfrmJvCharEditDlg.acSmallExecute(Sender: TObject);
begin
  UnCheckAll;
  acSmall.Checked := true;
  lvCharacters.ViewStyle := vsSmallIcon;
end;

procedure TfrmJvCharEditDlg.acListExecute(Sender: TObject);
begin
  UnCheckAll;
  acList.Checked := true;
  lvCharacters.ViewStyle := vsList;
end;

procedure TfrmJvCharEditDlg.acReportExecute(Sender: TObject);
begin
  UnCheckAll;
  acReport.Checked := true;
  lvCharacters.ViewStyle := vsReport;
  lvCharacters.Columns[0].Width := -2;
end;

procedure TfrmJvCharEditDlg.lvCharactersResize(Sender: TObject);
begin
  lvCharacters.Columns[0].Width := -2;
end;

procedure TfrmJvCharEditDlg.acCheckSelExecute(Sender: TObject);
var i:integer;
begin
  with lvCharacters do
    for i := 0 to Items.Count - 1 do
      if Items[i].Selected then
        Items[i].Checked := true;
end;

procedure TfrmJvCharEditDlg.acUnCheckSelExecute(Sender: TObject);
var i:integer;
begin
  with lvCharacters do
    for i := 0 to Items.Count - 1 do
      if Items[i].Selected then
        Items[i].Checked := false;
end;

procedure TfrmJvCharEditDlg.lvCharactersEnter(Sender: TObject);
begin
  if lvCharacters.Selected = nil then
    lvCharacters.Selected := lvCharacters.Items[0];
  lvCharacters.Selected.Focused := true;
end;

procedure TfrmJvCharEditDlg.cbFontsCloseUp(Sender: TObject);
begin
  lvCharacters.Font.Name := cbFonts.Text;
end;

procedure TfrmJvCharEditDlg.cbFontsKeyPress(Sender: TObject;
  var Key: Char);
begin
  if Key = #13 then
    cbFontsCloseUp(Sender);
end;

procedure TfrmJvCharEditDlg.lvCharactersAdvancedCustomDrawItem(
  Sender: TCustomListView; Item: TListItem; State: TCustomDrawState;
  Stage: TCustomDrawStage; var DefaultDraw: Boolean);
begin
  DefaultDraw := true;
  if Item.Checked then
  begin
    lvCharacters.Canvas.Font.Style := [fsBold];
    lvCharacters.Canvas.Font.Color := clWhite;
    lvCharacters.Canvas.Brush.Color := clMaroon;
  end;
end;

procedure TfrmJvCharEditDlg.lvCharactersSelectItem(Sender: TObject;
  Item: TListItem; Selected: Boolean);
begin
  if Item <> nil then
    Caption := Format(SFormCaption,[integer(Item.Data),integer(Item.Data),cAsciiNames[Char(Item.Data)]]);
end;

end.

