unit UnitFrmPermanentEdit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, ComCtrls, Buttons, UnitClipQueue, Menus,
  UnitFrmHotKey, UnitFrmPermanentNew, ImgList;



type
  TFrmPermanentEdit = class(TForm)

    {$REGION 'default'}
    pmGetAs: TPopupMenu;
    PlaintText1: TMenuItem;
    DIBPicture1: TMenuItem;
    CopiedFiles1: TMenuItem;
    RichTExt1: TMenuItem;
    pmSaveGroup: TPopupMenu;
    pnlBottom: TPanel;
    btnCancel: TButton;
    btnSaveGroup: TSpeedButton;
    btnSave: TButton;
    ilPics: TImageList;
    pmInsertKey: TPopupMenu;
    MILeft1: TMenuItem;
    MIRight1: TMenuItem;
    MIUp1: TMenuItem;
    MIDown1: TMenuItem;
    MITab1: TMenuItem;
    MIBackspace1: TMenuItem;
    MIHome1: TMenuItem;
    MIEnd1: TMenuItem;
    MIDelete1: TMenuItem;
    MIInsert1: TMenuItem;
    MISpace1: TMenuItem;
    N1: TMenuItem;
    pmInsertCommands: TPopupMenu;
    MIClear1: TMenuItem;
    MIWait1: TMenuItem;
    MIDate1: TMenuItem;
    MIClipboard1: TMenuItem;
    MIPopupItem1: TMenuItem;
    MIRun1: TMenuItem;
    MIClearPopupClips1: TMenuItem;
    pnlOptional: TPanel;
    pnlTop: TPanel;
    pnlCaption: TPanel;
    lblCaptionHelp: TLabel;
    Label2: TLabel;
    txtItemName: TEdit;
    pnlClip: TPanel;
    Label4: TLabel;
    pnlPreview: TPanel;
    pPreview: TImage;
    reItemText: TRichEdit;
    mItemText: TMemo;
    pmRightClick: TPopupMenu;
    MICut1: TMenuItem;
    MICopy1: TMenuItem;
    MIPaste1: TMenuItem;
    MIDelete2: TMenuItem;
    N3: TMenuItem;
    MISelectAll1: TMenuItem;
    MIPasteAs1: TMenuItem;
    pnlKeys: TPanel;
    Panel8: TPanel;
    Panel9: TPanel;
    Panel10: TPanel;
    btnInsert: TSpeedButton;
    btnCommands: TSpeedButton;
    MIWindows1: TMenuItem;
    MIEditHistory1: TMenuItem;
    MIConfiguration1: TMenuItem;
    MIRemovedClips1: TMenuItem;
    MIEditClipboard1: TMenuItem;
    MIPermanentClips1: TMenuItem;
    MISearch1: TMenuItem;
    pnlDescription: TPanel;
    Shape2: TShape;
    lblCommands: TLabel;
    Shape3: TShape;
    Label1: TLabel;
    MISelectAll2: TMenuItem;
    N4: TMenuItem;
    Copy1: TMenuItem;
    Cut1: TMenuItem;
    MISelectWordLeft1: TMenuItem;
    MISelectWordRight1: TMenuItem;
    MIKeyCombination1: TMenuItem;
    Examples1: TMenuItem;
    MIHighlightCurrentLine1: TMenuItem;
    MIHighlighttoBeginningofPage1: TMenuItem;
    MIHighlightToEnd1: TMenuItem;
    MIDeleteWordRight1: TMenuItem;
    MIDeleteWordLeft1: TMenuItem;
    N5: TMenuItem;
    Examples2: TMenuItem;
    MIGooglesearchClipboard1: TMenuItem;
    MIEditalltextinEditor1: TMenuItem;
    MIClipboardTimestamp1: TMenuItem;
    MIPastethefirst5PopupClips1: TMenuItem;
    InsertClipboard1: TMenuItem;
    MIEnter1: TMenuItem;
    PasteSelected1: TMenuItem;
    ClipboardOnly1: TMenuItem;
    MIPromptforInput1: TMenuItem;
    btnPreview: TSpeedButton;
    ClipboardFindandReplace1: TMenuItem;
    DisableClipboardMonitoring1: TMenuItem;
    DeletePopupClip1: TMenuItem;
    MimicTypingforClip1: TMenuItem;
    ClipboardTrim1: TMenuItem;
    Removedoublelinefeedsfromclipboard1: TMenuItem;
    lblGroup: TLabel;
    EditClipboard1: TMenuItem;
    ReplaceDoubleSpaces1: TMenuItem;
    ReplaceDoubleLinefeeds1: TMenuItem;
    ReplaceTabswithSpaces1: TMenuItem;
    UpperCase1: TMenuItem;
    LowerCase1: TMenuItem;
    CapitalizeWords1: TMenuItem;
    btnMoreToggle: TSpeedButton;
    InverseCase1: TMenuItem;
    RemoevLinefeeds1: TMenuItem;
    CopyandWaitforClip1: TMenuItem;
    PushClipboard1: TMenuItem;
    PopFirsttoClipboard1: TMenuItem;
    PopLasttoClipboard1: TMenuItem;
    emporaryClips1: TMenuItem;
    N7: TMenuItem;
    N8: TMenuItem;
    N9: TMenuItem;
    Insert1: TMenuItem;
    Select1: TMenuItem;
    PasteMode1: TMenuItem;
    N2: TMenuItem;
    PlacePopupCliponClipboard1: TMenuItem;
    PasteDefault1: TMenuItem;
    PopupClips1: TMenuItem;
    MoveClip1: TMenuItem;
    WaitForNewClip1: TMenuItem;
    ClipboardtoTextfile1: TMenuItem;
    CopyNormal1: TMenuItem;
    AppendtoClipboard1: TMenuItem;
    AppendClipboard1: TMenuItem;
    PlaintextOnly1: TMenuItem;
    FormattedOnly1: TMenuItem;
    cbIgnoreNewlines: TCheckBox;
    SplitClipboard1: TMenuItem;
    MISplitClipboardbylinefeeds1: TMenuItem;
    MISplitClipboardLoop1: TMenuItem;
    cbxClipType: TComboBox;
    Label3: TLabel;
    JavaScript1: TMenuItem;
    MIExtractLinks: TMenuItem;
    MISaveClipboard: TMenuItem;
    MINewClip: TMenuItem;
    pnlMacroResults: TPanel;
    txtMacroPreview: TMemo;
    pnlMacroStatus: TPanel;
    lblMacroStatus: TLabel;
    btnClosePreviewMacro: TButton;

    procedure btnCancelClick(Sender: TObject);
    procedure btnSaveClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btnClosePreviewMacroClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure btnSaveGroupClick(Sender: TObject);
    procedure GroupMenuClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure btnMoreToggleClick(Sender: TObject);
    procedure txtItemNameChange(Sender: TObject);
    procedure MIAllClick(Sender: TObject);
    procedure btnInsertClick(Sender: TObject);
    procedure btnCommandsClick(Sender: TObject);
    procedure txtItemNameEnter(Sender: TObject);
    procedure txtItemNameExit(Sender: TObject);
    procedure MICut1Click(Sender: TObject);
    procedure MICopy1Click(Sender: TObject);
    procedure MIPaste1Click(Sender: TObject);
    procedure MIDelete2Click(Sender: TObject);
    procedure MISelectAll1Click(Sender: TObject);
    procedure pmRightClickPopup(Sender: TObject);
    procedure MIKeyCombination1Click(Sender: TObject);
    procedure MIHighlightCurrentLine1Click(Sender: TObject);
    procedure MIHighlighttoBeginningofPage1Click(Sender: TObject);
    procedure MISelecttobeginning1Click(Sender: TObject);
    procedure MIHighlightToEnd1Click(Sender: TObject);
    procedure MIDeleteWordRight1Click(Sender: TObject);
    procedure MIDeleteWordLeft1Click(Sender: TObject);
    procedure MIGooglesearchClipboard1Click(Sender: TObject);
    procedure MIEditalltextinEditor1Click(Sender: TObject);
    procedure MIClipboardTimestamp1Click(Sender: TObject);
    procedure MIPastethefirst5PopupClips1Click(Sender: TObject);
    procedure btnPreviewClick(Sender: TObject);
    procedure Removedoublelinefeedsfromclipboard1Click(Sender: TObject);
    procedure lblGroupContextPopup(Sender: TObject; MousePos: TPoint;
      var Handled: Boolean);
    procedure mItemTextKeyPress(Sender: TObject; var Key: Char);
    procedure mItemTextKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure mItemTextKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure MISplitClipboardbylinefeeds1Click(Sender: TObject);
    procedure cbxClipTypeChange(Sender: TObject);
    procedure MIExtractLinksClick(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    {$ENDREGION}
  private
    { Private declarations }
    clip : TClipItem;
    IsNew : boolean;
    index : integer;
    group : string;
    overridegroup : string;
    format : TClipFormatType;
    HasNewData : boolean;
    HasNewCaption: boolean;
    NewDatIsClip : boolean;
    DialogMode : boolean;

    procedure ShowItem(ci : TClipItem); overload;
    procedure UpdateCaret;
    procedure setOverride(group : string);
  protected
    procedure CreateParams(var Params: TCreateParams); override;
    procedure HidePreviews;
    procedure ShowEditMode;
    procedure ShowPreviewMode;
  public
    { Public declarations }
    function ShowFormNew(group : string) : integer;
    function ShowForm(
        group : string;
        itemindex : integer) : integer; overload;

    procedure SetNewItem(ci : TClipItem; var modalresult : integer);  overload;
    procedure SetNewItem( clip : string; caption :string='' ); overload;

    procedure PopupItemClick(sender : Tobject);

    function ShowAsDialog(var caption : string; var clip : string) : boolean;
    function isKeystrokeCommand : boolean;
    function isPlainText : boolean;
    function isJavaScript : boolean;
    procedure setKeystrokeCommand(value : boolean);
  end;

var
  FrmPermanentEdit: TFrmPermanentEdit;

implementation

uses  Clipbrd, UnitMisc, UnitTWideChar, StrUtils, UnitFrmPermanentPreview,
  UnitPaste, ShLwApi, UnitKeyboardQuery, UnitToken, UnitClipDatabase, UnitJS,
  UnitACPopupClicks, UnitPopupGenerate, UnitFrmEditHistory;

{$R *.dfm}

const
    JAVASCRIPT_IDX = 2;
    KEYSTROKE_COMMAND_IDX = 1;
    PLAINTEXT_IDX = 0;
procedure TFrmPermanentEdit.setKeystrokeCommand;
begin
    if value then begin
        cbxClipType.ItemIndex := KEYSTROKE_COMMAND_IDX;
    end else begin
        cbxClipType.ItemIndex := PLAINTEXT_IDX;
    end;

    cbxClipTypeChange(cbxClipType);
end;
function TFrmPermanentEdit.isKeystrokeCommand : boolean;
begin
    result := cbxClipType.ItemIndex = KEYSTROKE_COMMAND_IDX;
end;
function TFrmPermanentEdit.isJavaScript : boolean;
begin
    result := cbxClipType.ItemIndex = JAVASCRIPT_IDX;
end;
function TFrmPermanentEdit.isPlainText : boolean;
begin
    result := cbxClipType.ItemIndex = PLAINTEXT_IDX;
end;


procedure TFrmPermanentEdit.ShowEditMode;
begin
    pnlMacroResults.Visible := false;
    pnlCaption.Visible := true;
    pnlClip.Visible := true;
end;
procedure TFrmPermanentEdit.ShowPreviewMode;
begin
    pnlMacroResults.Visible := true;
    pnlCaption.Visible := false;
    pnlClip.Visible := false;
end;

procedure TFrmPermanentEdit.HidePreviews;
begin
    mItemText.Visible := false;
    reItemText.Visible := false;
    pPreview.Visible := false;
end;
procedure TFrmPermanentEdit.cbxClipTypeChange(Sender: TObject);
var i, j : integer;
begin
    mItemText.WordWrap := cbxClipType.ItemIndex <> JAVASCRIPT_IDX;
    if not TJavaScript.IsJavaScript(mItemText.Text) and (cbxClipType.ItemIndex = JAVASCRIPT_IDX) then begin
        mItemText.Text := TJavaScript.getStartMacro + #13#10 + TJavaScript.getEndMacro;
    end;

    for i := 0 to pnlKeys.ControlCount  - 1 do begin
        if  pnlkeys.Controls[i] is TPanel then begin
            for j := 0 to TPanel(pnlkeys.Controls[i]).ControlCount - 1 do   begin
                TPanel(pnlkeys.Controls[i]).Controls[j].Enabled := not isPlainText;
            end;
        end;
    end;

    btnInsert.Enabled := not isPlainText;
    btnCommands.Enabled := not isPlainText;
    pnlDescription.Visible := not isPlainText;
    btnPreview.Enabled := not isPlainText;
    if (isPlainText) then
        ShowEditMode;
end;

procedure TFrmPermanentEdit.CreateParams(var Params: TCreateParams);
begin
    inherited CreateParams(Params);
    // allow context taskbar context menu and
    // show me on the taskbar - independant of main form
    with Params do begin
        ExStyle := ExStyle or WS_EX_APPWINDOW;
        WndParent := FrmPermanent.Handle;
    end;
end;

procedure TFrmPermanentEdit.FormActivate(Sender: TObject);
begin
    if self.Visible then
        if self.ActiveControl = nil then begin
            self.SetFocusedControl(self.txtItemName);
        end;
end;

procedure TFrmPermanentEdit.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    self.HasNewData := false;
    self.NewDatIsClip := false;
    self.HasNewCaption := false;
    FrmPermanentPreview.Hide;
end;
procedure TFrmPermanentEdit.FormCreate(Sender: TObject);
begin
//    clip := TClipItem.Create;

    self.clientheight := pnlTop.Height + pnlBottom.height;
    pnlTop.Align := alClient;

    SHAutoComplete(txtItemName.Handle,
        SHACF_AUTOAPPEND_FORCE_OFF or SHACF_AUTOSUGGEST_FORCE_OFF);

{    SHAutoComplete(mItemText.Handle,
        SHACF_AUTOAPPEND_FORCE_OFF or SHACF_AUTOSUGGEST_FORCE_OFF);
 }
end;
procedure TFrmPermanentEdit.FormShow(Sender: TObject);
begin
    self.ShowEditMode;
    //bgOptional.Height := 10;
    self.txtItemName.SetFocus;

    setOverride(overridegroup);
end;

procedure TFrmPermanentEdit.GroupMenuClick(Sender: TObject);
begin
    self.overridegroup := TMenuItem(sender).caption;
    lblGroup.Caption := '&Group [' +self.overridegroup + ']' ;
end;


function TFrmPermanentEdit.ShowAsDialog(var caption : string; var clip : string) : boolean;
var windowCaption : string;
begin
    DialogMode := true;
    self.SetNewItem(clip, caption);
//    self.cbKeystrokes.Checked := true;

    self.btnSaveGroup.Enabled := false;
    self.lblGroup.Visible := false;

    windowCaption := self.Caption;
    self.Caption := 'Edit Macro';
    result := false;
    if self.ShowModal <> mrCancel then begin
        result := true;
        caption := txtItemName.Text;
        clip := mItemText.Text;
    end;
    self.Caption := windowCaption;
    DialogMode := false;
    self.btnSaveGroup.Enabled := true;
    self.lblGroup.Visible := true;
end;

procedure TFrmPermanentEdit.setOverride(group : string);
begin
    self.overridegroup := group;
    lblGroup.Caption := '&Group [' + self.overridegroup + ']' ;
end;



procedure TFrmPermanentEdit.lblGroupContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean);
begin
    btnSaveGroupClick(self);
end;

procedure TFrmPermanentEdit.MIHighlightCurrentLine1Click(Sender: TObject);
begin
    self.Update;
    mItemText.SelText := '[END][KEY="001024SHIFT+HOME"]';
end;
procedure TFrmPermanentEdit.MIHighlighttoBeginningofPage1Click(Sender: TObject);
begin
    self.Update;
    mItemText.SelText := '[KEY="011024CTRL+SHIFT+HOME"]';


end;
procedure TFrmPermanentEdit.MIHighlightToEnd1Click(Sender: TObject);
begin
    self.Update;
    mItemText.SelText := '[KEY="011023CTRL+SHIFT+END"]';
end;
procedure TFrmPermanentEdit.MISelecttobeginning1Click(Sender: TObject);
begin
    self.Update;
    mItemText.SelText := '[END][KEY="001024SHIFT+HOME"]';
end;

procedure TFrmPermanentEdit.mItemTextKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
{    if (key = VK_BACK) and ([ssCtrl]=shift) then begin
        key := 0;
        Paste.SendTextWithKeystrokes('[KEYS][KEY="001025SHIFT+LEFT"][DEL]');
    end;}
end;
procedure TFrmPermanentEdit.mItemTextKeyPress(Sender: TObject; var Key: Char);
begin
    if Key = ^A then begin
        (Sender as TMemo).SelectAll;
        Key := #0;
    end;
{    if (key = #127)  then begin
        key := #0;
    end;}
end;
procedure TFrmPermanentEdit.mItemTextKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
{    if (key = VK_BACK) and ([ssCtrl]=shift) then begin
        key := 0;
    end;}
end;

procedure TFrmPermanentEdit.btnInsertClick(Sender: TObject);
var p : TPoint;
begin
    p := btnInsert.Parent.ClientToScreen(Point(btnInsert.Left, btnInsert.top));
    pmInsertKey.Popup(p.X+btnInsert.Width, p.y);
end;
procedure TFrmPermanentEdit.btnCommandsClick(Sender: TObject);
var p : TPoint;
begin
    p := btnCommands.Parent.ClientToScreen(Point(btnCommands.Left, btnCommands.top));
    pmInsertCommands.Popup(p.X+btnCommands.Width, p.y);
end;




procedure TFrmPermanentEdit.SetNewItem(clip : string; caption :string='' );
begin
    self.clip := TClipITem.Create;
    self.clip.SetFromPlainText(clip);
    self.clip.SetDisplayText(caption);

    self.ShowItem(self.clip);

    self.txtItemName.Text := caption;
    setOverride(FrmPermanent.GetPermanentPath);

    self.IsNew := true;

    if not self.DialogMode then
        self.ShowModal;
end;

procedure TFrmPermanentEdit.SetNewItem(ci : TClipItem; var modalresult : integer);
begin
    if (self.clip<>nil) then myfree(self.clip);

    self.clip := ci.CloneClip;
    self.ShowItem(ci);

    self.txtItemName.text := '';
    setOverride(FrmPermanent.GetPermanentPath);

    self.IsNew := true;
    self.index := -1;

    modalresult := self.ShowModal;
end;


function TFrmPermanentEdit.ShowFormNew(group : string) : integer;
begin
    self.IsNew := true;
    self.overridegroup := group;
    self.index := -1;
    txtItemName.text := '';
    mItemText.Lines.clear;

    self.clip := TClipItem.Create;
    self.clip.SetFromPlainText('');
    self.clip.SetDisplayText('');
    self.ShowItem(self.clip);

    result := self.ShowModal;
end;
function TFrmPermanentEdit.ShowForm(
        group : string; itemindex : integer) : integer;
var s : string;
    prefix : string;
    procedure RefreshPopup;

        var i : integer;
        cur, s : string;
        mi : TMenuItem;
    begin
        pmSaveGroup.Items.Clear;
        if self.overridegroup = '' then self.overridegroup := self.group;
        cur := self.overridegroup;

        for i  := 0 to FrmPermanent.PermFoldersGetCount - 1 do begin
            s := FrmPermanent.PermFoldersGetItem(i);
            mi := pmSaveGroup.CreateMenuItem;
            mi.Caption := s;
            if (s = cur) then begin
                mi.Checked := true;
            end;
            mi.OnClick := self.GroupMenuClick;

            pmSaveGroup.Items.add(mi);
        end;
    end;

begin
    self.clip := TClipItem.Create;
    TClipDatabase.LoadPermanent(clip, itemindex, group);

    self.IsNew := false;
    self.index := itemindex;
    setOverride(group);

    HidePreviews;

    self.index := ItemIndex;
    self.group := group;

//    cbKeystrokes.Checked := false;
    setKeystrokeCommand(false);
    cbIgnoreNewlines.Checked := false;;




    self.ShowItem(self.clip);

    txtItemName.text := self.clip.getDisplayText;

    prefix := uppercase(leftstr(mItemText.Text,6));

    cbIgnoreNewlines.Enabled := false;
    cbIgnoreNewlines.checked := false;

    if StartsText(KEYS_STR, mItemText.text) then begin
        setKeystrokeCommand(true);
        cbIgnoreNewlines.Enabled := true;
    end;

    if TJavaScript.isJavaScript(mItemText.text) then begin
        cbxClipType.ItemIndex := JAVASCRIPT_IDX;
        cbxClipTypeChange(cbxClipType);
    end;

    if StartsText(KEYS_IGNORENL_STR, mItemText.text) then begin
        cbIgnoreNewlines.Enabled := true;
        setKeystrokeCommand(true);
        cbIgnoreNewlines.Checked := true;
    end;

    if (cbIgnoreNewlines.Checked) then begin
        s := mItemText.Text;
        delete(s, 1, length(KEYS_IGNORENL_STR));
        mItemText.Text := s;
    end else if isKeystrokeCommand then begin
        s := mItemText.Text;
        delete(s,1,length(KEYS_STR));
        mItemText.Text := s;
    end;

    result := self.ShowModal;
end;




procedure TFrmPermanentEdit.txtItemNameChange(Sender: TObject);
begin
    if not DialogMode then begin
        btnsave.Enabled := txtItemName.Text <> '';
        btnSaveGroup.Enabled := btnsave.Enabled;
        lblGroup.Enabled := btnSave.Enabled;
    end else begin
        btnsave.Enabled := (txtItemName.Text <> '') and (mItemText.Text<>'');
    end;
end;
procedure TFrmPermanentEdit.txtItemNameEnter(Sender: TObject);
begin
    if not DialogMode then
        lblCaptionHelp.Visible := true;
end;
procedure TFrmPermanentEdit.txtItemNameExit(Sender: TObject);
begin
    lblCaptionHelp.Visible := false;
end;

procedure TFrmPermanentEdit.btnSaveGroupClick(Sender: TObject);
var i : integer;
    cur, s : string;
    mi : TMenuItem;
    var p : TPoint;
begin
    pmSaveGroup.Items.Clear;
    if self.overridegroup = '' then self.overridegroup := self.group;
    cur := self.overridegroup;

    for i  := 0 to FrmPermanent.PermFoldersGetCount - 1 do begin
        s := FrmPermanent.PermFoldersGetItem(i);
        mi := pmSaveGroup.CreateMenuItem;
        mi.Caption := s;
        if (s = cur) then begin
            mi.Checked := true;
        end;
        mi.OnClick := self.GroupMenuClick;

        pmSaveGroup.Items.add(mi);
    end;

    p := btnSaveGroup.Parent.ClientToScreen(Point(btnSaveGroup.Left, btnSaveGroup.top));
    pmSaveGroup.Popup(p.X+btnSaveGroup.Width, p.y);
end;
procedure TFrmPermanentEdit.btnMoreToggleClick(Sender: TObject);
begin
    if btnMoreToggle.caption = '&More' then begin
        btnMoreToggle.caption := 'L&ess';
        btnMoreToggle.Glyph := nil;
        ilPics.GetBitmap(1, btnMoreToggle.Glyph );

        pnlOptional.Visible := true;
        pnlOptional.Top := pnlBottom.Top - pnlOptional.Height;

        self.clientheight := self.ClientHeight + pnlOptional.height;
    end else begin
        btnMoreToggle.caption := '&More';

        pnlOptional.visible := false;
        self.clientheight := self.ClientHeight - pnlOptional.height;

        btnMoreToggle.Glyph := nil;
        ilPics.GetBitmap(0, btnMoreToggle.Glyph );
    end;
end;
procedure TFrmPermanentEdit.btnPreviewClick(Sender: TObject);
var
    s,s2,token : string;
    b : boolean;
    prefix : string;

    procedure HandleJavaScriptError(errorMessage : string; scriptContent : string);
    var
        s, originalMessage : string;
        location, line : string;
        linenbr : integer;
        sl : TStringList;
        i : integer;
        cnt, linelength : integer;
    begin
        originalMessage := errorMessage;
        if (pos('Microsoft JScript', errorMessage) > 0) then begin
            UnitToken.TokenString(errorMessage, TJavaScript.GetScriptName + '(');
            location := UnitToken.TokenString(errorMessage,')');
            try
                location := UnitToken.TokenString(location,',');
                linenbr := SysUtils.StrToInt(location);
                linenbr := linenbr - TJavaScript.GetMainLineOffset(scriptContent)-1;
            except
            end;
            UnitToken.TokenString(errorMessage,':');

            txtMacroPreview.Text := 'JavaScript Error line('+IntToStr(linenbr)+'): '+ errorMessage;


            mItemText.SelStart := mitemText.Perform(EM_LINEINDEX, linenbr, 0);
            mItemText.SelLength := length(mItemText.Lines[linenbr]);

        end else begin
            txtMacroPreview.Text := errorMessage;
        end;
    end;
var js : TJavaScript;
begin
    ShowPreviewMode;

    txtMacroPreview.Lines.Clear;
    self.FocusControl(txtMacroPreview);

    s := uppercase(mItemText.text);
    s2 := TokenString(s,'[INDEX=',false);
    if (s<>'') then begin
        //[INDEX=$i]
        token := TokenString(s,']',false);
        s := mItemText.text;
        s := StringReplace(s,'[index='+token+']', '',[rfReplaceAll,rfIgnoreCase]);
        s := StringReplace(s,token, IntToStr(0),[rfReplaceAll,rfIgnoreCase]);
    end else begin
        s := mItemText.text;
    end;
    if ContainsText(s,'[STAYOPEN]') then begin
        s := StringReplace(s,'[STAYOPEN]', '',[rfReplaceAll,rfIgnoreCase]);
    end;

    case cbxClipType.ItemIndex of
    0:
        begin
            Paste.SendPlainText(s);
        end;
    1:
        begin
            if cbIgnoreNewlines.Checked then begin
                s := KEYS_IGNORENL_STR + s;
            end else begin
                s := KEYS_STR + s;
            end;
            Paste.SendMacro(s);
        end;
    2:
        begin
            js := TJavaScript.Create;
            if not js.executeJS(application.handle,Paste, s) then begin
                HandleJavaScriptError(js.getLastErr, js.GeneratedScript);
            end;
            myfree(js);
        end;
    end;
end;
procedure TFrmPermanentEdit.btnClosePreviewMacroClick(Sender: TObject);
var btn : TButton;
begin
    ShowEditMode;
    self.SetFocusedControl(mItemText);
//    btn := TButton(sender);
//    self.Update;
//
//    if (btn.caption = 'DATE') then begin
//        mItemText.SelText := '[' + btn.Caption + '="mm/dd/yyyy"]';
//    end else if (btn.caption = 'POPUPITEM') then begin
//        mItemText.SelText := '[' + btn.Caption + '="0"]';
//    end else begin
//        mItemText.SelText := '[' + btn.Caption + ']';
//    end;
end;

procedure TFrmPermanentEdit.btnSaveClick(Sender: TObject);
begin
    if not DialogMode then begin
        try
            FrmPermanentPreview.Hide;

            TClipDatabase.StartBatch;
            // if the group changed, just save to the end of the list
            if (self.group <> self.overridegroup) then begin
                self.index := -1;
                self.group := self.overridegroup;
            end;

            if (self.IsNew) or (self.index = -1) then begin
                self.index := TClipDatabase.getCountPermanent(self.group);
            end;

            if (format in [FT_UNICODE, FT_TEXT]) then begin
                if (cbIgnoreNewlines.Checked) then begin
                    self.clip.SetFromPlainText(KEYS_IGNORENL_STR+mItemText.text);

                end else if (isKeystrokeCommand) then begin
                    self.clip.SetFromPlainText(KEYS_STR+mItemText.text);
                end else begin
                    self.clip.SetFromPlainText(mItemText.text);
                end;
            end;
            self.clip.SetDisplayText(txtItemName.text);
            TClipDatabase.SavePermanent(self.clip, self.index, self.group);

            TClipDatabase.EndBatch;
        finally
            myfree(self.clip);
        end;
    end;
    self.ModalResult := mrOK;
end;
procedure TFrmPermanentEdit.btnCancelClick(Sender: TObject);
begin
    self.ModalResult := mrCancel;
    self.Hide;
    myfree(self.clip);
end;


procedure TFrmPermanentEdit.MIAllClick(Sender: TObject);


    function isKeystroke(str : string) : boolean;
{
    pv_left, pv_right, pv_up, pv_down,
    , pv_home, pv_end,
    pv_tab, pv_delete, pv_space, pv_enter}
    const
        TEMP_DELIM = '&';
        KEYS_STR = ' LEFT RIGHT UP DOWN HOME END TAB SPACE ENTER ';

    begin
        result := TokenInString(
            str,
            TEMP_DELIM,
            ReplaceText(KEYS_STR,' ',TEMP_DELIM)
        );
    end;
var mi : TMenuItem;
    s : string;
begin
    mi := TMenuItem(sender);
    s := uppercase(mi.Caption);

    self.Update;


    if (s = 'DATE') then begin
        mItemText.SelText := '[DATE="mm/dd/yyyy"]';
    end else if (s = 'WAIT') then begin
        mItemText.SelText := '[WAIT=100]';
    end else if (AnsiStartsText('SHOW PROMPT',s)) then begin
        mItemText.SelText := '[PROMPT="Enter Data"]';

    end else if (s = 'POPUPITEM') then begin
        mItemText.SelText := '[POPUPITEM="0"]';
    end else if (AnsiStartsText('POPUPCLIP', s)) then begin
        mItemText.SelText := '[POPUPITEM=0]';

    end else if (s= 'BACKSPACE') then begin
        mItemText.SelText := '[BACK REPEAT=1]';
    end else if (s= 'DELETE') then begin
        mItemText.SelText := '[DEL REPEAT=1]';
    end else if (s='SPACEBAR') then begin
        mItemText.SelText := '[SPACE REPEAT=1]';
    end else if (s= 'DATE') then begin
        mItemText.SelText := '[DATE="mm/dd/yyyy"]';
    end else if (AnsiStartsText('CLIPBOARD STATE', s)) then begin
        mItemText.SelText := '[CLIPBRD]';
    end else if (AnsiStartsText('CURRENT CLIPBOARD', s)) then begin
        mItemText.SelText := '[CLIPBRDCURRENT]';
    end else if (s= 'DELETE CLIPBOARD') then begin
        mItemText.SelText := '[CLEAR]';
        end else if (s= 'CONFIGURATION') then begin
            mItemText.SelText := '[WINDOWCONFIG]';
        end else if (s= 'EDIT HISTORY') then begin
            mItemText.SelText := '[WINDOWHISTORY]';
        end else if (s= 'REMOVED CLIPS') then begin
            mItemText.SelText := '[WINDOWREMOVED]';
        end else if (s= 'EDIT CLIPBOARD') then begin
            mItemText.SelText := '[WINDOWCLIPBOARD]';
        end else if (s= 'PERMANENT CLIPS') then begin
            mItemText.SelText := '[WINDOWPERMANENT]';
        end else if (s= 'SEARCH AND PASTE') then begin
            mItemText.SelText := '[WINDOWSEARCH=""]';
    end else if (s= 'ALL') then begin
        mItemText.SelText := '[SELECTALL]';
    end else if (s= 'WORD LEFT') then begin
        mItemText.SelText := '[SELECTLEFT REPEAT=1]';
    end else if (s= 'WORD RIGHT') then begin
        mItemText.SelText := '[SELECTRIGHT REPEAT=1]';
     end else if (s= 'PASTE SELECTED') then begin
        mItemText.SelText := '[WINDOWPASTESEL]';
    end else if (AnsiStartsText('CLIPBOARD ONLY', s)) then begin
    	mItemText.seltext := '[CLIPBOARDONLY]';
    end else if (s = 'FIND AND REPLACE') then begin
        mItemText.SelText := '[CLIPBOARDFIND="" REPLACE=""]';
    end else if (s = 'REPLACE DOUBLE SPACES') then begin
        mItemText.SelText := '[CLIPBOARDFIND="  " REPLACE=" "]';
    end else if (s = 'REPLACE DOUBLE LINEFEEDS') then begin
        mItemText.SelText := '[CLIPBOARDFIND="\n\n" REPLACE="\n"]';
    end else if (s = 'REPLACE TABS WITH SPACES') then begin
        mItemText.SelText := '[CLIPBOARDFIND="\t" REPLACE="    "]';
    end else if (s = 'REMOVE LINEFEEDS') then begin
        mItemText.SelText := '[CLIPBOARDFIND="\n" REPLACE=""]';
        end else if (s = 'UPPER CASE') then begin
        mItemText.SelText := '[CLIPBOARDUPPER]';
        end else if (s = 'LOWER CASE') then begin
        mItemText.SelText := '[CLIPBOARDLOWER]';
        end else if (s = 'CAPITALIZE WORDS') then begin
        mItemText.SelText := '[CLIPBOARDCAPWORDS]';
        end else if (s = 'INVERSE CASE') then begin
        mItemText.SelText := '[CLIPBOARDINVERSE]';
    end else if (AnsiStartsText('DISABLE CLIP', s)) then begin
        mItemText.SelText := '[DISABLEMONITORING]';
    end else if (AnsiStartsText('MIMIC TYPING', s)) then begin
        mItemText.SelText := '[MIMIC]';
    end else if (AnsiStartsText('TRIM', s)) then begin
        mItemText.SelText := '[TRIMCLIPBOARD]';
    end else if (AnsiStartsText('COPY AND', s)) then begin
        mItemText.SelText := '[COPYWAIT=2000]';
    end else if (s = 'PUSH CLIPBOARD') then begin
        mItemText.SelText := '[PUSHCLIPBOARD]';
    end else if (AnsiStartsText('POP FIRST', s)) then begin
        mItemText.SelText := '[POPFIRST]';
    end else if (AnsiStartsText('POP LAST', s)) then begin
        mItemText.SelText := '[POPLAST]';
    end else if (AnsiStartsText('PASTE', s)) then begin
        mItemText.SelText := '[PASTEDEFAULT]';

    {Popup Clips}
    end else if (s= 'DELETE CLIP') then begin
        mItemText.SelText := '[DELETECLIP=0]';
    end else if (s= 'DELETE ALL CLIPS') then begin
        mItemText.SelText := '[CLEARPOPUP]';
    end else if (AnsiStartsText('PLACE CLIP', s)) then begin
        mItemText.SelText := '[TOCLIPBOARD=0]';
    end else if (s= 'MOVE CLIP') then begin
        mItemText.SelText := '[MOVECLIP="0" TO="1"]';
    end else if (s= 'SAVE CLIPBOARD') then begin
        mItemText.SelText := '[SAVECLIPBOARD]';
    end else if (s= 'NEW CLIP') then begin
        mItemText.SelText := '[NEWCLIP=""]';



    end else if (s='RUN') then begin
        mItemText.SelText := '[RUN][ENDRUN]';

    end else if s = 'WAIT FOR NEW CLIP' then begin
        mItemText.SelText := '[WAITFORCLIP]';
    end else if s = 'CLIPBOARD TO TEXTFILE' then begin
        mItemText.SelText := '[TOTEXTFILE=""]';

    end else if (s='COPY NORMAL') then begin
        mItemText.selText := '[COPY="NORMAL"]';
        end else if (s='PREPEND CLIPBOARD') then begin
            mItemText.selText := '[COPY="PREPEND"]';
        end else if (s='APPEND CLIPBOARD') then begin
            mItemText.selText := '[COPY="APPEND"]';
        end else if (s='PLAINTEXT ONLY') then begin
            mItemText.selText := '[COPY="PLAIN"]';
        end else if (s='FORMATTED ONLY') then begin
            mItemText.selText := '[COPY="FORMAT"]'
    end else if (s='SPLIT CLIPBOARD') then begin
        mItemText.SelText := '[CLIPBOARDSPLIT SEPARATOR=""][SPLITPIECE=0][SPLITPIECE=1]';
    end else if (s='SPLIT CLIPBOARD LOOP') then begin
        mItemText.SelText := '[CLIPBOARDSPLIT SEPARATOR=""][SPLITLOOP="$i"][SPLITPIECE=$i][ENDSPLITLOOP]';

    end else if isKeystroke(s)  then begin
        mItemText.SelText := '[' + s + ' REPEAT=1]';
    end else begin
        mItemText.SelText := '[' + s + ']';
    end;
end;
procedure TFrmPermanentEdit.MIKeyCombination1Click(Sender: TObject);
var hkd : THotkeyData;
begin
    if FrmHotkey.GetHotkey(
        hkd.alt, hkd.shft, hkd.ctrl, hkd.win,
        hkd.key,
        hkd.name
    ) then begin

       self.Update;


       mItemText.seltext := '[KEY="'+ frmHotkey.toHKstring(hkd)  +'"]';
    end;
end;

procedure TFrmPermanentEdit.MICopy1Click(Sender: TObject);
begin
    mItemText.CopyToClipboard;
end;
procedure TFrmPermanentEdit.MICut1Click(Sender: TObject);
begin
    mItemText.CutToClipboard;
end;
procedure TFrmPermanentEdit.MIDelete2Click(Sender: TObject);
begin
    mItemText.SelText := '';
end;
procedure TFrmPermanentEdit.MIDeleteWordLeft1Click(Sender: TObject);
begin
    self.Update;
    mItemText.SelText := '[KEY="010008CTRL+BACKSPACE"]';
end;
procedure TFrmPermanentEdit.MIDeleteWordRight1Click(Sender: TObject);
begin
    self.Update;
    mItemText.SelText := '[KEY="01002ECTRL+DELETE"]';
end;
procedure TFrmPermanentEdit.MIPaste1Click(Sender: TObject);
begin
    mItemText.PasteFromClipboard;
end;

procedure TFrmPermanentEdit.UpdateCaret;
begin
    if (mItemText.SelStart = 0) and (mItemText.SelLength = 0) then
        mItemTExt.SelStart := length(mItemText.Text);
end;

procedure TFrmPermanentEdit.MIGooglesearchClipboard1Click(Sender: TObject);
begin
    self.Update;
    mItemText.SelText := '[RUN]http://www.google.com/search?q=[CLIPBRD]';

end;
procedure TFrmPermanentEdit.MIEditalltextinEditor1Click(Sender: TObject);
begin
    self.Update;
    mItemText.SelText := '[SELECTALL][COPY][WINDOWCLIPBOARD]';

end;
procedure TFrmPermanentEdit.MIExtractLinksClick(Sender: TObject);
var
    s : AnsiString;
    ResStream: TResourceStream;
const NL = #13#10;
begin

    ResStream := TResourceStream.Create(hInstance, 'EXTRACT_JS', RT_RCDATA);
    setlength(s, ResStream.Size);
    ResStream.Read(s[1],length(s));
    myfree(ResStream);

    cbxClipType.ItemIndex := JAVASCRIPT_IDX;

    mItemText.text := TJavaScript.getStartNoMacro +
    '   var urls = extractURLs(clipboardStr);'+ NL +
    '   if (urls==null) return;'+ NL +
    '   var result = "";'+NL+
    '   for (var i=0;i<urls.length;i++) {'+NL+
    '       result += urls[i]+"\r\n";'+NL+
    '   }'+NL+
    '   manuallyExecuteMacro("[CLIPBOARDONLY]"+result);'+NL+
    TJavaScript.getEndNoMacro + NL +
    string(s);
end;

procedure TFrmPermanentEdit.MIClipboardTimestamp1Click(Sender: TObject);
begin
self.Update;

    mItemText.SelText := '[DATE="hh:mm ampm"]: [CLIPBRD]';
end;
procedure TFrmPermanentEdit.MIPastethefirst5PopupClips1Click(Sender: TObject);
begin
self.Update;
    mItemText.SelText := '[POPUPITEM=0]' + #13#10 +
    '[POPUPITEM=1]' + #13#10 +
    '[POPUPITEM=2]' + #13#10 +
    '[POPUPITEM=3]' + #13#10 +
    '[POPUPITEM=4]';
end;

procedure TFrmPermanentEdit.MISplitClipboardbylinefeeds1Click(Sender: TObject);
begin
    self.Update;
    mItemText.SelText := '[CLIPBOARDSPLIT SEPARATOR="\n"][SPLITLOOP="$i"][SPLITPIECE=$i][TAB][ENDSPLITLOOP]';
end;

procedure TFrmPermanentEdit.Removedoublelinefeedsfromclipboard1Click(Sender: TObject);
begin
  self.Update;
    mItemText.SelText := '[CLIPBOARDFIND="\n\n" REPLACE="\n"]';
end;


procedure TFrmPermanentEdit.MISelectAll1Click(Sender: TObject);
begin
    mItemText.SelectAll;
end;

procedure TFrmPermanentEdit.pmRightClickPopup(Sender: TObject);
    procedure AddFormat(format : integer; description : string);
    var mi : TMenuItem;
    begin
        if Clipbrd.clipboard.HasFormat(format) then begin
            mi := TMenuItem.Create(MIPasteAs1);
            mi.Caption := description;
            mi.Hint := IntToStr(format);
            mi.OnClick := self.PopupItemClick;
            MIPasteAs1.Add(mi);
        end;

    end;

begin
    if mItemText.Visible then begin
        MISelectAll1.Enabled := mItemText.text <> '';
        MIDelete2.Enabled := mItemText.SelText <> '';
        MICut1.Enabled := MIDelete2.Enabled;
        MICopy1.Enabled := MIDelete2.Enabled;
    end else begin
        MISelectAll1.Enabled := false;
        MIDelete2.Enabled := false;
        MICut1.Enabled := false;
        MICopy1.Enabled := false;
    end;

    MIPasteAs1.Clear;
    AddFormat(CF_TEXT, 'Plain Text');
    AddFormat(CF_WAVE, 'Wave Audio');
    AddFormat(CF_DIB, 'DIB (Picture)');
    AddFormat(CF_HDROP, 'File(s)');
    AddFormat(UnitMisc.GetCF_RICHTEXT, 'RichText');
    AddFormat(UnitMisc.GetCF_HTML, 'HTML');
    AddFormat(CF_UNICODETEXT, 'Unicode');

end;
procedure TFrmPermanentEdit.PopupItemClick(sender: Tobject);
begin
    clip.GetClipboardItem(0, SysUtils.StrToInt(TMenuItem(sender).Hint));
    self.ShowItem(clip);
end;


procedure TFrmPermanentEdit.ShowItem(ci: TClipItem);
var
    s : string;
begin
    HidePreviews;

    format := ci.GetFormatType;
    case format of
    FT_PICTURE:
        begin
            pPreview.Visible := true;
            ci.GetDIB(pPreview.Picture);
        end;
    FT_RICHTEXT, FT_HTML:
        begin
            reItemText.Visible := true;
            reItemText.PlainText := false;
            reItemText.Lines.Clear;
            if format = FT_HTML then begin
                ci.GetUTF8Text(s);
            end else begin
                ci.GetRichText(s);
            end;
            reItemText.Text := s;
        end;
    FT_FILE:
        begin
            reItemText.Visible := true;
            reItemText.PlainText := true;
            reItemText.Lines.Clear;
            reItemText.Text := ci.GetAsPlaintext;
        end;
    else
        begin
            mItemText.Visible := true;

            mitemtext.Text := ci.GetAsPlaintext;
        end;
    end;
end;

end.
