unit UnitMainTools; interface uses SysUtils, Classes, Windows, Forms, Controls, SpTBXTabs, TBX, SciLexer, SciLexerMemo, ExtCtrls, Graphics, sciKeyBindings, ComCtrls, TB2Item, sciLexerMod, ScintillaLanguageManager, Menus, SpTBXItem, Registry, ShellApi, DDEMan, IdFTP, IdFTPList, IdException, JvInspector, JvComCtrls; type TDocument = class(TCollectionItem) private FSelLength: Integer; FSelStart: Integer; FFileName: String; FCode: String; FReadOnly: Boolean; FTopLine: Integer; FHighlighter: String; FTitle: String; FModified: Boolean; FNotesText: String; FAutoCompleteItems: String; FKeywords: String; FCallTips: String; procedure SetFileName(const Value: String); published property FileName: String read FFileName write SetFileName; property Title: String read FTitle write FTitle; property Code: String read FCode write FCode; property SelStart: Integer read FSelStart write FSelStart; property SelLength: Integer read FSelLength write FSelLength; property Highlighter: String read FHighlighter write FHighlighter; property ReadOnly: Boolean read FReadOnly write FReadOnly; property TopLine: Integer read FTopLine write FTopLine; property Modified: Boolean read FModified write FModified; property NotesText: String read FNotesText write FNotesText; property Keywords: String read FKeywords write FKeywords; property CallTips: String read FCallTips write FCallTips; property AutoCompleteItems: String read FAutoCompleteItems write FAutoCompleteItems; public constructor Create(ACollection: TCollection; AHighlighter: String); reintroduce; destructor Destroy; reintroduce; function Untitled: Boolean; function Save: Boolean; end; type TDocCollection = class(TCollection) private FHighlighter: String; FActiveDocument: TDocument; public constructor Create(AHighlighter: String); reintroduce; function Add(AFilename: String; AHighlighter: String = ''): TDocument; reintroduce; function Open(AFilename: String; AHighlighter: String = ''): Integer; function Save(AIndex: Integer; AFilename: String = ''): Boolean; procedure Close(AIndex: Integer); procedure Activate(Document: Integer; RestoreCaret: Boolean; SaveLastDoc: Boolean = True); overload; procedure Activate(Document: TDocument; RestoreCaret: Boolean; SaveLastDoc: Boolean = True); overload; published property Highlighter: String read FHighlighter write FHighlighter; property ActiveDocument: TDocument read FActiveDocument write FActiveDocument; end; type TStringArray = array of string; function GetMenuItem(Caption: String; eParent: TTBCustomItem = nil): TTBCustomItem; function GetCat: String; function GetCIItem(eName: String; eParent: TJvCustomInspectorItem = nil): TJvCustomInspectorItem; function GetCIItemByValue(eValue: String; eParent: TJvCustomInspectorItem = nil): TJvCustomInspectorItem; function FindSettingsNode(eText: String; eParent: TTreeNode = nil): TTreeNode; procedure LoadPlugins; function GetAllIncludeFiles(eMask: String): TStringArray; function GetCurrLang(FileName: String = ''): TSciLangItem; procedure FillCodeExplorer(Lang: String); function IEInstalled: Boolean; function GetAMXXDir(ListenServer: Boolean): String; function CloseDocument(eDocument: TDocument; SaveActiveDoc: Boolean = False): Boolean; function AddExtension(eFilename, eHighlighter: String): String; function ShowColorDialog(var Color: TColor; ePaintImage: TImage): Boolean; procedure LoadCodeSnippets(Lang: String); procedure SetProgressStatus(eStatus: String); function IsNumeric(eText: String): Boolean; procedure ActivateProjects(Index: Integer; JumpToLastDoc: Boolean); procedure ReloadIni; procedure SelectLanguage(Lang: String); procedure ShowProgress(ReadOnly: Boolean); procedure HideProgress; procedure mIRCDDE(Service, Topic, Cmd: string); function mIRCGet(Service, Topic, Item: string): String; function GetAllDirs: TStringList; procedure SetProxySettings; function TryConnect: Integer; var PawnProjects: TDocCollection; CPPProjects: TDocCollection; OtherProjects: TDocCollection; Started: Boolean; ActiveDoc: TDocument; Cancel: Boolean; OldPercent: Integer; // We don't need to update caption when the new percentage equals to the old CurrProjects: Integer; implementation uses UnitfrmMain, UnitfrmSettings, UnitLanguages, UnitfrmSelectColor, UnitCodeSnippets, UnitTextAnalyze, UnitCodeUtils, UnitfrmAutoIndent, UnitPlugins; function GetCat: String; begin if frmMain.mnuPawn.Checked then Result := 'Pawn' else if frmMain.mnuCPP.Checked then Result := 'C++' else if frmMain.mnuHTML.Checked then Result := 'HTML' else Result := 'Other'; end; function GetCIItem(eName: String; eParent: TJvCustomInspectorItem = nil): TJvCustomInspectorItem; var i: integer; begin eName := LowerCase(eName); Result := nil; if eParent = nil then begin for i := 0 to frmMain.jviCode.Root.Count -1 do begin if LowerCase(frmMain.jviCode.Root.Items[i].DisplayName) = eName then Result := frmMain.jviCode.Root.Items[i] else if frmMain.jviCode.Root.Items[i].Count <> 0 then Result := GETCIItem(eName, frmMain.jviCode.Root.Items[i]); if Assigned(Result) then exit; end; end else begin for i := 0 to eParent.Count -1 do begin if LowerCase(eParent.Items[i].DisplayName) = eName then Result := eParent.Items[i] else if eParent.Items[i].Count <> 0 then Result := GETCIItem(eName, eParent.Items[i]); if Assigned(Result) then exit; end; end; end; function GetCIItemByValue(eValue: String; eParent: TJvCustomInspectorItem = nil): TJvCustomInspectorItem; var i: integer; begin eValue := LowerCase(eValue); Result := nil; if eParent = nil then begin for i := 0 to frmMain.jviCode.Root.Count -1 do begin if LowerCase(frmMain.jviCode.Root.Items[i].DisplayValue) = eValue then Result := frmMain.jviCode.Root.Items[i] else if frmMain.jviCode.Root.Items[i].Count <> 0 then Result := GetCIItemByValue(eValue, frmMain.jviCode.Root.Items[i]); if Assigned(Result) then exit; end; end else begin for i := 0 to eParent.Count -1 do begin if LowerCase(eParent.Items[i].DisplayValue) = eValue then Result := eParent.Items[i] else if eParent.Items[i].Count <> 0 then Result := GetCIItemByValue(eValue, eParent.Items[i]); if Assigned(Result) then exit; end; end; end; function FindSettingsNode(eText: String; eParent: TTreeNode = nil): TTreeNode; var i: integer; begin Result := nil; if eText = '' then exit; eText := LowerCase(eText); if eParent = nil then begin for i := 0 to frmSettings.trvSettings.Items.Count -1 do begin if LowerCase(frmSettings.trvSettings.Items[i].Text) = eText then Result := frmSettings.trvSettings.Items[i] else if frmSettings.trvSettings.Items[i].Count <> 0 then Result := FindSettingsNode(eText, frmSettings.trvSettings.Items[i]); if Assigned(Result) then exit; end; end else begin for i := 0 to eParent.Count -1 do begin if LowerCase(eParent[i].Text) = eText then Result := eParent[i] else if eParent[i].Count <> 0 then Result := FindSettingsNode(eText, eParent[i]); if Assigned(Result) then exit; end; end; end; function GetMenuItem(Caption: String; eParent: TTBCustomItem = nil): TTBCustomItem; var i: integer; begin Result := nil; if eParent = nil then begin for i := 0 to frmMain.tbxMenu.Items.Count -1 do begin if frmMain.tbxMenu.Items[i].Caption = Caption then begin Result := frmMain.tbxMenu.Items[i]; break; end else if frmMain.tbxMenu.Items[i].Count <> 0 then begin Result := GetMenuItem(Caption, frmMain.tbxMenu.Items[i]); if Assigned(Result) then break; end; end; end else begin for i := 0 to eParent.Count -1 do begin if eParent.Items[i].Caption = Caption then begin Result := eParent.Items[i]; break; end else if eParent.Items[i].Count <> 0 then begin Result := GetMenuItem(Caption, eParent.Items[i]); if Assigned(Result) then break; end; end; end; end; procedure LoadPlugins; var i: integer; ePConfig: TStringList; eRec: TSearchRec; eFound: Boolean; eItem: TListItem; begin ePConfig := TStringList.Create; ePConfig.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'config\plugins.cfg'); if FindFirst(ExtractFilePath(ParamStr(0)) + 'plugins\*.dll', faAnyFile, eRec) = 0 then begin repeat if (eRec.Name[1] <> '.') and (eRec.Attr and faDirectory <> faDirectory) then begin eFound := False; for i := 0 to ePConfig.Count -1 do begin if Pos(#32 + eRec.Name, ePConfig[i]) <> 0 then begin // We don't need to handle unloaded plugins... if Pos('LOADED', ePConfig[i]) = 1 then begin // Loaded eItem := frmSettings.lvPlugins.Items.Add; eItem.Caption := '-'; eItem.SubItems.Add(eRec.Name); eItem.SubItems.Add('-'); eItem.SubItems.Add('Unloaded'); LoadPlugin(eItem); eFound := True; end; break; end; end; if not eFound then begin with frmSettings.lvPlugins.Items.Add do begin Caption := '-'; SubItems.Add(eRec.Name); SubItems.Add('-'); SubItems.Add('Unloaded'); end; end; end; until FindNext(eRec) <> 0; end; ePConfig.Destroy; end; function GetAllIncludeFiles(eMask: String): TStringArray; var eSearchRec: TSearchRec; eStr: TStringList; i: integer; begin if Between(eMask, '<', '>') <> '' then eMask := Between(eMask, '<', '>', True) else if Between(eMask, '"', '"') <> '' then eMask := Between(eMask, '"', '"', True); eStr := TStringList.Create; if GetAMXXDir(False) <> '' then begin if FindFirst(GetAMXXDir(False) + 'scripting\include\*.inc', faAnyFile, eSearchRec) = 0 then begin repeat if (eSearchRec.Name[1] <> '.') and (eSearchRec.Attr and faDirectory <> faDirectory) then begin if ExtractFileExt(eMask) <> '' then eStr.Add(eSearchRec.Name) else eStr.Add(ChangeFileExt(eSearchRec.Name, '')); end; until (FindNext(eSearchRec) <> 0); end; if FindFirst(GetAMXXDir(False) + 'scripting\*.inc', faAnyFile, eSearchRec) = 0 then begin repeat if (eSearchRec.Name[1] <> '.') and (eSearchRec.Attr and faDirectory <> faDirectory) then begin if ExtractFileExt(eMask) <> '' then eStr.Add(eSearchRec.Name) else eStr.Add(ChangeFileExt(eSearchRec.Name, '')); end; until (FindNext(eSearchRec) <> 0); end; end; if (not ActiveDoc.Untitled) then begin if FindFirst(GetAMXXDir(False) + 'scripting\include\*.inc', faAnyFile, eSearchRec) = 0 then begin repeat if (eSearchRec.Name[1] <> '.') and (eSearchRec.Attr and faDirectory <> faDirectory) then begin if ExtractFileExt(eMask) <> '' then eStr.Add(eSearchRec.Name) else eStr.Add(ChangeFileExt(eSearchRec.Name, '')); end; until (FindNext(eSearchRec) <> 0); end; end; SetLength(Result, eStr.Count); for i := 0 to eStr.Count -1 do Result[i] := eStr[i]; eStr.Destroy; end; function GetCurrLang(FileName: String = ''): TSciLangItem; var eExt, eLang: String; begin if FileName = '' then eExt := LowerCase(ExtractFileExt(ActiveDoc.FileName)) else eExt := LowerCase(ExtractFileExt(FileName)); if (eExt = '.sma') or (eExt = '.inc') or (eExt = '.inl') then eLang := 'Pawn' else if (eExt = '.cpp') or (eExt = '.h') then eLang := 'C++' else if (eExt = '.htm') or (eExt = '.html') then eLang := 'HTML' else if (eExt = '.xml') then eLang := 'XML' else if (eExt = '.sql') then eLang := 'SQL' else eLang := 'null'; Result := frmMain.sciEditor.LanguageManager.LanguageList.Find(eLang); end; procedure FillCodeExplorer(Lang: String); function AddItem(eParent: TTreeNode; eText: String): TTreeNode; begin if eParent = nil then Result := frmMain.trvExplorer.Items.Add(nil, eText) else Result := frmMain.trvExplorer.Items.AddChild(eParent, eText); with Result do begin ImageIndex := 42; SelectedIndex := 42; end; end; var eTemp: TTreeNode; begin frmMain.trvExplorer.Items.BeginUpdate; if (Lang = 'Pawn') then begin // Pawn AddItem(nil, 'Constants'); eTemp := AddItem(nil, 'Defined'); AddItem(eTemp, 'CVars'); AddItem(nil, 'Forwards'); AddItem(nil, 'Included'); eTemp := AddItem(nil, 'Methods'); AddItem(eTemp, 'Default'); AddItem(eTemp, 'Events'); AddItem(eTemp, 'Stocks'); AddItem(nil, 'Natives'); AddItem(nil, 'Variables'); end; frmMain.trvExplorer.Items.EndUpdate; end; function IEInstalled: Boolean; var eReg: TRegistry; eVersion: String; begin eReg := TRegistry.Create(KEY_READ); with eReg do begin RootKey := HKEY_LOCAL_MACHINE; OpenKey('Software\Microsoft\Internet Explorer', False); if ValueExists('Version') then eVersion := ReadString('Version') else eVersion := ''; CloseKey; Free; end; Result := Pos('6.0', eVersion) = 1; end; function GetAMXXDir(ListenServer: Boolean): String; begin if Started then begin if ListenServer then Result := frmSettings.txtAMXXDir.Text else if Length(frmSettings.txtPawnCompilerPath.Text) > 8 then Result := IncludeTrailingPathDelimiter(Copy(ExtractFilePath(frmSettings.txtPawnCompilerPath.Text), 1, Length(ExtractFilePath(frmSettings.txtPawnCompilerPath.Text)) - 10)) else Result := ''; end else Result := ''; end; function CloseDocument(eDocument: TDocument; SaveActiveDoc: Boolean = False): Boolean; var Collection: TDocCollection; begin case frmMain.tsMain.ActiveTabIndex of 0: Collection := PawnProjects; 1: Collection := CPPProjects; else Collection := OtherProjects; end; Result := True; if (eDocument.Modified) then begin case MessageBox(frmMain.Handle, PChar(Format(lCloseModify, [ExtractFileName(eDocument.FileName)])), PChar(Application.Title), MB_ICONQUESTION + MB_YESNOCANCEL) of mrYes: begin frmMain.mnuSave.Click; if not eDocument.Untitled then Collection.Close(eDocument.Index); end; mrNo: Collection.Close(eDocument.Index); mrCancel: Result := False; end; end else Collection.Close(eDocument.Index); end; function AddExtension(eFilename, eHighlighter: String): String; begin if ExtractFileExt(eFilename) = '' then begin if eHighlighter = 'Pawn' then Result := eFilename + '.sma'; if eHighlighter = 'C++' then Result := eFilename + '.cpp'; if eHighlighter = 'HTML' then Result := eFilename + '.html'; if eHighlighter = 'SQL' then Result := eFilename + '.sql'; if eHighlighter = 'XML' then Result := eFilename + '.xml'; end else Result := eFilename; end; procedure LoadCodeSnippets(Lang: String); var i: integer; CSItem: TSpTBXItem; begin for i := frmMain.tbxCodeSnippets.Items.Count -1 downto 6 do frmMain.tbxCodeSnippets.Items.Delete(i); with GetSnippetList(Lang) do begin for i := 0 to Count -1 do begin CSItem := TSpTBXItem.Create(frmMain.tbxCodeSnippets); CSItem.Caption := Strings[i]; CSItem.OnClick := frmMain.OnCodeSnippetClick; frmMain.tbxCodeSnippets.Items.Add(CSItem); end; end; end; function ShowColorDialog(var Color: TColor; ePaintImage: TImage): Boolean; begin frmSelectColor.Hexa.SelectedColor := Color; frmSelectColor.HSL.SelectedColor := Color; frmSelectColor.chkDefault1.Checked := Color = clDefault; frmSelectColor.chkDefault2.Checked := Color = clDefault; frmSelectColor.chkNone1.Checked := Color = clNone; frmSelectColor.chkNone2.Checked := Color = clNone; frmSelectColor.OldSwatch.Color := Color; Result := frmSelectColor.ShowModal = mrOk; if Result then begin if frmSelectColor.chkDefault1.Checked then Color := clDefault else if frmSelectColor.chkNone1.Checked then Color := clNone else Color := frmSelectColor.NewSwatch.Color; ePaintImage.Canvas.Pen.Color := $008396A0; ePaintImage.Canvas.Brush.Color := Color; ePaintImage.Canvas.Rectangle(0, 0, ePaintImage.Width, ePaintImage.Height); end; end; procedure SetProgressStatus(eStatus: String); var Percent: Integer; begin if not Started then exit; if (frmMain.pbLoading.Position <> frmMain.pbLoading.Max) and (frmMain.pbLoading.Max <> 0) then Percent := Round((frmMain.pbLoading.Position / frmMain.pbLoading.Max) * 100) else Percent := 0; if frmMain.pbLoading.Caption = IntToStr(Percent) + '% - ' + eStatus then exit; OldPercent := Percent; frmMain.pbLoading.Caption := IntToStr(Percent) + '% - ' + eStatus; end; function IsNumeric(eText: String): Boolean; var i: integer; begin Result := Length(eText) > 0; if Result then begin for i := 1 to Length(eText) do Result := (Result) and (Pos(eText[i], '0123456789') <> 0); end; end; procedure ActivateProjects(Index: Integer; JumpToLastDoc: Boolean); var Collection: TDocCollection; i: integer; TabItem: TSpTBXTabItem; OldIndex: Integer; begin if not Plugin_ProjectsChange(CurrProjects, Index, True) then begin Started := False; frmMain.tsMain.ActiveTabIndex := CurrProjects; Started := True; exit; end; OldIndex := CurrProjects; with frmMain do begin // no save here, it saves when another tab is being activated... case Index of 0: Collection := PawnProjects; // Pawn 1: Collection := CPPProjects; // C++ else Collection := OtherProjects; // Other end; Started := False; // dont run this command twice frmMain.tsMain.Items[Index].Checked := True; // select tab CurrProjects := Index; tsDocuments.Items.Clear; for i := 0 to Collection.Count -1 do begin TabItem := TSpTBXTabItem.Create(tsDocuments); TabItem.Caption := TDocument(Collection.Items[i]).Title; TabItem.OnSelect := frmMain.OnTabSelect; tsDocuments.Items.Add(TabItem); end; Started := True; if JumpToLastDoc then begin Started := False; tsDocuments.Items[Collection.ActiveDocument.Index].Checked := True; Collection.Activate(Collection.ActiveDocument.Index, True); Started := True; end; Plugin_ProjectsChange(OldIndex, Index, False); end; end; procedure ReloadIni; var i: integer; KeyCommand: TSciKeyCommand; Item: TListItem; Ident: string; begin //> INI-Values eConfig.ReadString('Misc', 'Theme', 'Office11Adaptive')) then TBXSetTheme(eConfig.ReadString('Misc', 'Theme', 'Office11Adaptive')); //> Update Settings-Dialog '-1'; if eConfig.ReadString('Editor', 'AutoDisable', '1500') <> '-1' then frmSettings.txtAUDisable.Text := eConfig.ReadString('Editor', 'AutoDisable', '1500'); if foldFold in frmMain.sciEditor.Folding then begin case frmMain.sciEditor.FoldMarkerType of sciMarkArrows: frmSettings.cboCodeFolding.ItemIndex := 0; sciMarkBox: frmSettings.cboCodeFolding.ItemIndex := 1; sciMarkCircle: frmSettings.cboCodeFolding.ItemIndex := 2; sciMarkPlusMinus: frmSettings.cboCodeFolding.ItemIndex := 3; end; end else frmSettings.cboCodeFolding.ItemIndex := 4; frmSettings.PaintCaretFore(frmMain.sciEditor.Caret.ForeColor); frmSettings.CaretFore := frmMain.sciEditor.Caret.ForeColor; frmSettings.PaintCaretBack(frmMain.sciEditor.Caret.LineBackColor); frmSettings.CaretBack := frmMain.sciEditor.Caret.LineBackColor; frmSettings.txtPeriod.Text := IntToStr(frmMain.sciEditor.Caret.Period); frmSettings.chkShowCaret.Checked := frmMain.sciEditor.Caret.LineVisible; if frmSettings.chkIndentGuides.Checked then frmMain.sciEditor.Indentation := frmMain.sciEditor.Indentation + [IndentationGuides] else frmMain.sciEditor.Indentation := frmMain.sciEditor.Indentation - [IndentationGuides]; frmMain.sciEditor.AutoCloseBraces := frmSettings.chkAutoCloseBraces.Checked; frmMain.sciEditor.AutoCloseQuotes := frmSettings.chkAutoCloseQuotes.Checked; frmMain.sciEditor.BraceHilite := frmSettings.chkHighlightBraces.Checked; frmMain.sciEditor.ClearUndoAfterSave := frmSettings.chkClearUndoAfterSave.Checked; frmSettings.chkDisableAC.Checked := eConfig.ReadBool('Editor', 'Disable_AC', False); frmSettings.chkDisableCT.Checked := eConfig.ReadBool('Editor', 'Disable_CT', False); frmMain.sciAutoComplete.Disabled := frmSettings.chkDisableAC.Checked; frmMain.sciCallTips.Disabled := frmSettings.chkDisableCT.Checked; { Shortcuts } frmSettings.lvShortcuts.Items.BeginUpdate; try frmSettings.lvShortcuts.Clear; for i := 0 to frmMain.sciEditor.KeyCommands.Count - 1 do begin KeyCommand := frmMain.sciEditor.KeyCommands.Items[i] as TSciKeyCommand; Ident := 'Unknown'; IntToIdent(KeyCommand.Command, Ident, Sci_KeyboardCommandMap); if Ident <> 'No Command' then begin // Important for Control Chars, the user mustn't change the values for it... Item := frmSettings.lvShortcuts.Items.Add; Item.Caption:= Ident; Item.SubItems.Add(ShortCutToText(KeyCommand.ShortCut)); Item.Data := KeyCommand; end; end; finally frmSettings.lvShortcuts.Items.EndUpdate; end; { FTP Settings } frmSettings.txtHost.Text := eConfig.ReadString('FTP', 'Host', ''); frmSettings.txtPort.Text := eConfig.ReadString('FTP', 'Port', '21'); frmSettings.txtUsername.Text := eConfig.ReadString('FTP', 'Username', ''); frmSettings.txtPassword.Text := eConfig.ReadString('FTP', 'Password', ''); frmSettings.txtDefaultDir.Text := eConfig.ReadString('FTP', 'DefaultDir', ''); frmSettings.chkPassive.Checked := eConfig.ReadBool('FTP', 'Passive', True); with frmMain.IdFTP do begin Host := frmSettings.txtHost.Text; Port := StrToInt(frmSettings.txtPort.Text); Username := frmSettings.txtUsername.Text; Password := frmSettings.txtPassword.Text; Passive := frmSettings.chkPassive.Checked; end; { FTP Proxy } frmSettings.cboProxy.ItemIndex := eConfig.ReadInteger('Proxy', 'ProxyType', 0); frmSettings.txtProxyHost.Text := eConfig.ReadString('Proxy', 'Host', ''); frmSettings.txtProxyPort.Text := eConfig.ReadString('Proxy', 'Port', '8080'); frmSettings.txtUsername.Text := eConfig.ReadString('Proxy', 'Username', ''); frmSettings.txtProxyPassword.Text := eConfig.ReadString('Proxy', 'Password', ''); SetProxySettings; { Compiler } frmSettings.txtPawnCompilerPath.Text := eConfig.ReadString('Pawn-Compiler', 'Path', ''); frmSettings.txtPawnArgs.Text := eConfig.ReadString('Pawn-Compiler', 'Args', ''); frmSettings.txtPawnOutput.Text := IncludeTrailingPathDelimiter(eConfig.ReadString('Pawn-Compiler', 'DefaultOutput', '')); if frmSettings.txtPawnOutput.Text = '\' then frmSettings.txtPawnOutput.Text := ''; frmSettings.txtCPPCompilerPath.Text := eConfig.ReadString('CPP-Compiler', 'Path', ''); frmSettings.txtCPPCompilerArguments.Text := eConfig.ReadString('CPP-Compiler', 'Args', ''); frmSettings.txtCPPOutput.Text := IncludeTrailingPathDelimiter(eConfig.ReadString('CPP-Compiler', 'DefaultOutput', '')); if frmSettings.txtCPPOutput.Text = '\' then frmSettings.txtCPPOutput.Text := ''; { HL } frmSettings.txtHLExec.Text := eConfig.ReadString('Half-Life', 'Filename', ''); frmSettings.txtCustomParameters.Text := eConfig.ReadString('Half-Life', 'Params', ''); frmSettings.txtAMXXDir.Text := IncludeTrailingPathDelimiter(eConfig.ReadString('Half-Life', 'AMXXListen', '')); if frmSettings.txtAMXXDir.Text = '\' then frmSettings.txtAMXXDir.Text := ''; { Code-Snippets } frmSettings.ftcCodeSnippets.ActiveTab := 0; { Misc } frmSettings.txtDefaultName.Text := eConfig.ReadString('Misc', 'DefaultPluginName', 'New Plug-In'); frmSettings.txtDefaultVersion.Text := eConfig.ReadString('Misc', 'DefaultPluginVersion', '1.0'); frmSettings.txtDefaultAuthor.Text := eConfig.ReadString('Misc', 'DefaultPluginAuthor', 'Your Name'); case eConfig.ReadInteger('Misc', 'SaveNotesTo', 0) of 0: frmSettings.optFileComment.Checked := True; 1: frmSettings.optConfig.Checked := True; else frmSettings.optDontSave.Checked := True; end; frmSettings.sldSpeed.Value := eConfig.ReadInteger('Misc', 'CPUSpeed', 5); if frmSettings.sldSpeed.Value <> 0 then eCPUSpeed := frmSettings.sldSpeed.Value else eCPUSpeed := 1; // otherwise the program would hang up frmSettings.txtLangDir.Text := IncludeTrailingPathDelimiter(eConfig.ReadString('Misc', 'LangDir', '')); frmSettings.chkShowStatusbar.Checked := eConfig.ReadBool('Misc', 'ShowStatusbar', True); frmMain.sbStatus.Visible := frmSettings.chkShowStatusbar.Checked; end; procedure SelectLanguage(Lang: String); begin frmMain.sciEditor.LanguageManager.SelectedLanguage := Lang; frmMain.mnuHPawn.Checked := Lang = 'Pawn'; frmMain.mnuHCPP.Checked := Lang = 'C++'; frmMain.mnuHHTML.Checked := Lang = 'HTML'; frmMain.mnuHSQL.Checked := Lang = 'SQL'; frmMain.mnuHXML.Checked := Lang = 'XML'; frmMain.mnuHNone.Checked := Lang = 'null'; end; procedure ShowProgress(ReadOnly: Boolean); var i: integer; begin if not Started then exit; frmMain.pnlLoading.Show; for i := 0 to frmMain.tsDocuments.Items.Count -1 do frmMain.tsDocuments.Items[i].Enabled := i = frmMain.tsDocuments.ActiveTabIndex; for i := 0 to frmMain.tsMain.Items.Count -1 do frmMain.tsMain.Items[i].Enabled := i = frmMain.tsMain.ActiveTabIndex; for i := 0 to frmMain.tbxMenu.Items.Count -1 do frmMain.tbxMenu.Items[i].Enabled := False; for i := 0 to frmMain.tbxToolbar.Items.Count -1 do frmMain.tbxToolbar.Items[i].Enabled := False; for i := 0 to frmMain.tbxEdit.Items.Count -1 do frmMain.tbxEdit.Items[i].Enabled := False; for i := 0 to frmMain.tbxCodeSnippets.Items.Count -1 do frmMain.tbxCodeSnippets.Items[i].Enabled := False; for i := 0 to frmMain.tcTools.Items.Count -1 do frmMain.tcTools.Items[i].Enabled := False; frmMain.ppmDocuments.Items.Enabled := False; frmMain.sciEditor.ReadOnly := ReadOnly; end; procedure HideProgress; var i: integer; begin if not Started then exit; frmMain.pnlLoading.Hide; for i := 0 to frmMain.tsDocuments.Items.Count -1 do frmMain.tsDocuments.Items[i].Enabled := True; for i := 0 to frmMain.tsMain.Items.Count -1 do frmMain.tsMain.Items[i].Enabled := True; for i := 0 to frmMain.tbxMenu.Items.Count -1 do frmMain.tbxMenu.Items[i].Enabled := True; for i := 0 to frmMain.tbxToolbar.Items.Count -1 do frmMain.tbxToolbar.Items[i].Enabled := True; for i := 0 to frmMain.tbxEdit.Items.Count -1 do frmMain.tbxEdit.Items[i].Enabled := True; for i := 0 to frmMain.tbxCodeSnippets.Items.Count -1 do frmMain.tbxCodeSnippets.Items[i].Enabled := True; for i := 0 to frmMain.tcTools.Items.Count -1 do frmMain.tcTools.Items[i].Enabled := True; frmMain.tiCPP.Enabled := eCPP; frmMain.mnuNewHeaderCPP.Enabled := eCPP; frmMain.mnuNewModule.Enabled := eCPP; frmMain.mnuNewUnit.Enabled := eCPP; frmMain.ppmDocuments.Items.Enabled := True; frmMain.sciEditor.ReadOnly := False; end; { TDocument } constructor TDocument.Create(ACollection: TCollection; AHighlighter: String); begin inherited Create(ACollection); FHighlighter := TDocCollection(ACollection).Highlighter; FModified := False; end; destructor TDocument.Destroy; begin inherited Destroy; end; function TDocument.Save: Boolean; var i: integer; F: Textfile; sLines: TStringList; sNotes: String; eFound: Boolean; begin if not Plugin_FileSave(FFilename, True) then begin Result := False; exit; end; Result := True; Cancel := False; ShowProgress(True); if (FileExists(FFileName)) and (frmSettings.chkMakeBaks.Checked) then begin try CopyFile(PChar(FFileName), PChar(FFileName + '.bak'), False); SetFileAttributes(PChar(FFileName + '.bak'), faHidden); if ActiveDoc = Self then frmMain.mnuRestoreBackup.Enabled := True; except MessageBox(Application.Handle, PChar(lFailedCreateBak), PChar(Application.Title), MB_ICONERROR); frmMain.mnuRestoreBackup.Enabled := False; end; end; try AssignFile(F, FFilename); Rewrite(F); if ActiveDoc = Self then begin sLines := TStringList(frmMain.sciEditor.Lines); sNotes := GetRTFText(frmMain.rtfNotes); end else begin sLines := TStringList.Create; sLines.Text := Code; sNotes := NotesText; end; frmMain.pbLoading.Max := sLines.Count -1; frmMain.pbLoading.Position := 0; // ... save file... for i := 0 to sLines.Count -1 do begin if Cancel then begin CloseFile(F); Cancel := False; exit; end; WriteLn(F, sLines[i]); frmMain.pbLoading.Position := i; SetProgressStatus('Saving File...'); Application.ProcessMessages; end; // ... and notes ... if frmSettings.optFileComment.Checked then begin WriteLn(F, GetCurrLang.CommentBoxStart + ' AMXX-Studio Notes - DO NOT MODIFY BELOW HERE'); WriteLn(F, GetCurrLang.CommentBoxMiddle + sNotes); WriteLn(F, GetCurrLang.CommentBoxEnd); CloseFile(F); end else begin CloseFile(F); sLines := TStringList.Create; i := 0; // line 1 should be a comment if FileExists(ParamStr(0) + 'config\Notes.dat') then sLines.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'config\Notes.dat') else begin sLines.Clear; // something must be wrong, clear sLines.Add('AMXX-Studio Notes - DO NOT MODIFY THIS FILE'); end; eFound := False; if sLines.Count > 2 then begin while i <> sLines.Count -1 do begin Inc(i, 2); if LowerCase(FFilename) = LowerCase(sLines[i -1]) then begin sLines[i] := sNotes; eFound := True; break; end; end; end; if not eFound then begin // no entry found sLines.Add(FFilename); sLines.Add(sNotes); end; sLines.SaveToFile(ExtractFilePath(ParamStr(0)) + 'config\Notes.dat'); sLines.Destroy; end; FModified := False; except Result := False; end; HideProgress; Plugin_FileSave(FFilename, False); end; procedure TDocument.SetFileName(const Value: String); begin FFileName := Value; FTitle := '< ' + IntToStr(Index +1) + #32 + ExtractFileName(Value) + ' >'; end; function TDocument.Untitled: Boolean; begin Result := Pos('\', FFilename) = 0; end; { TDocCollection } procedure TDocCollection.Activate(Document: Integer; RestoreCaret: Boolean; SaveLastDoc: Boolean = True); begin Activate(TDocument(Items[Document]), RestoreCaret, SaveLastDoc); end; procedure TDocCollection.Activate(Document: TDocument; RestoreCaret: Boolean; SaveLastDoc: Boolean = True); begin if not Plugin_DocChange(Document.Index, Document.FileName, Document.Highlighter, RestoreCaret, True) then begin Started := False; TSpTBXTabItem(frmMain.tsDocuments.Items[ActiveDoc.Index]).Checked := True; Started := True; exit; end; Screen.Cursor := crHourGlass; { Save old } if SaveLastDoc then begin ActiveDoc.Code := frmMain.sciEditor.Lines.Text; // saving is fast, but loading is usually slow because of code-folding... ActiveDoc.Highlighter := frmMain.sciEditor.LanguageManager.SelectedLanguage; ActiveDoc.ReadOnly := frmMain.sciEditor.ReadOnly; ActiveDoc.SelStart := frmMain.sciEditor.SelStart; ActiveDoc.SelLength := frmMain.sciEditor.SelLength; ActiveDoc.TopLine := frmMain.sciEditor.GetFirstVisibleLine; ActiveDoc.Modified := frmMain.sciEditor.Modified; ActiveDoc.NotesText := GetRTFText(frmMain.rtfNotes); ActiveDoc.Keywords := TSciKeywords(TSciLangItem(frmMain.sciEditor.LanguageManager.LanguageList.Find('Pawn').Keywords.Items[1])).Keywords.Text; ActiveDoc.CallTips := frmMain.sciCallTips.ApiStrings.Text; ActiveDoc.AutoCompleteItems := frmMain.sciAutoComplete.AStrings.Text; end; { Other } ActiveDoc := Document; // one global for save... FActiveDocument := Document; // ... and one for switch frmMain.sciEditor.EmptyUndoBuffer; { Load new } SelectLanguage(Document.Highlighter); frmMain.sciEditor.Lines.Clear; if Started then begin Started := False; frmMain.tsDocuments.Items[Document.Index].Checked := True; if (frmMain.Canvas.TextWidth(Document.FileName) > frmMain.mnuFilename.CustomWidth) and (not Document.Untitled) then frmMain.mnuFilename.Caption := ExtractFileName(Document.FileName) else frmMain.mnuFilename.Caption := Document.FileName; Started := True; end; frmMain.sciEditor.SetText(PChar(Document.Code)); SetRTFText(frmMain.rtfNotes, Document.NotesText); TSciKeywords(TSciLangItem(frmMain.sciEditor.LanguageManager.LanguageList.Find('Pawn').Keywords.Items[1])).Keywords.Text := ActiveDoc.Keywords; frmMain.sciCallTips.ApiStrings.Text := ActiveDoc.CallTips; frmMain.sciAutoComplete.AStrings.Text := ActiveDoc.AutoCompleteItems; frmMain.sciEditor.LanguageManager.Update; frmMain.sciEditor.ReadOnly := Document.ReadOnly; if Document.Modified then frmMain.mnuModified.Caption := lModified else frmMain.mnuModified.Caption := ''; frmMain.sciEditor.Modified := Document.Modified; if RestoreCaret then begin frmMain.sciEditor.SelStart := Document.SelStart; frmMain.sciEditor.SelLength := Document.SelLength; frmMain.sciEditor.LineScroll(0, (0 - frmMain.sciEditor.GetFirstVisibleLine) + Document.TopLine); end; frmMain.mnuRestoreBackup.Enabled := (FileExists(Document.FileName + '.bak')) and (not Document.Untitled); Screen.Cursor := crDefault; Plugin_DocChange(Document.Index, Document.FileName, Document.Highlighter, RestoreCaret, False); end; function TDocCollection.Add(AFilename: String; AHighlighter: String = ''): TDocument; var TabItem: TSpTBXTabItem; begin if AHighlighter = '' then AHighlighter := Highlighter; Result := TDocument.Create(Self, AHighlighter); with Result do begin Highlighter := AHighlighter; FileName := AFileName; if Filename = '' then begin // Empty document if AHighlighter = 'Pawn' then begin Title := '< ' + IntToStr(Count) + ' Untitled.sma >'; FileName := 'Untitled.sma'; end else if AHighlighter = 'C++' then begin Title := '< ' + IntToStr(Count) + ' Untitled.cpp >'; FileName := 'Untitled.cpp'; end else if AHighlighter = 'HTML' then begin Title := '< ' + IntToStr(Count) + ' Untitled.html >'; FileName := 'Untitled.html'; end else if AHighlighter = 'SQL' then begin Title := '< ' + IntToStr(Count) + ' Untitled.sql >'; FileName := 'Untitled.sql'; end else if AHighlighter = 'XML' then begin Title := '< ' + IntToStr(Count) + ' Untitled.xml >'; FileName := 'Untitled.xml'; end else begin Title := '< ' + IntToStr(Count) + ' Untitled.txt >'; FileName := 'Untitled.txt'; end; end else Title := '< ' + IntToStr(Count) + #32 + ExtractFileName(AFilename) + ' >'; if not Started then exit; if (Self = PawnProjects) and (frmMain.tsMain.ActiveTabIndex <> 0) then exit; if (Self = CPPProjects) and (frmMain.tsMain.ActiveTabIndex <> 1) then exit; if (Self = OtherProjects) and (frmMain.tsMain.ActiveTabIndex <> 2) then exit; TabItem := TSpTBXTabItem.Create(frmMain.tsDocuments); TabItem.Caption := Title; TabItem.OnSelect := frmMain.OnTabSelect; frmMain.tsDocuments.Items.Add(TabItem); end; end; procedure TDocCollection.Close(AIndex: Integer); var Collection: TDocCollection; i: integer; begin case frmMain.tsMain.ActiveTabIndex of 0: Collection := PawnProjects; 1: Collection := CPPProjects; else Collection := OtherProjects; end; if Collection = Self then begin frmMain.tsDocuments.Items.Delete(AIndex); frmMain.tsDocuments.Refresh; end; Delete(AIndex); for i := 0 to Count -1 do TDocument(Items[i]).Title := '< ' + IntToStr(i +1) + #32 + ExtractFileName(TDocument(Items[i]).FileName) + ' >'; if Collection = Self then begin for i := 0 to frmMain.tsDocuments.Items.Count -1 do TSpTBXTabItem(frmMain.tsDocuments.Items[i]).Caption := TDocument(Items[i]).Title; end; if Count = 0 then Add('', ''); if (AIndex -1 < Count) and (AIndex <> 0) then Activate(AIndex -1, True, False) else Activate(0, True, False); end; constructor TDocCollection.Create(AHighlighter: String); begin inherited Create(TDocument); Highlighter := AHighlighter; FActiveDocument := Add(''); end; function TDocCollection.Open(AFilename: String; AHighlighter: String = ''): Integer; var F: TextFile; i: integer; eString: String; eLines: TStringList; begin Result := -1; if not Plugin_FileLoad(AFilename, True) then exit; if not FileExists(AFilename) then begin MessageBox(frmMain.Handle, PChar(lInvalidFile), 'AMXX-Studio', MB_ICONWARNING); exit; end; if frmSettings.chkDontLoadFilesTwice.Checked then begin for i := 0 to Count -1 do begin if AnsiSameText(TDocument(Items[i]).FileName, AFilename) then begin Result := i; Activate(i, True); exit; end; end; end; if Assigned(ActiveDoc) then begin ActiveDoc.Code := frmMain.sciEditor.Lines.Text; // saving is fast, but loading is usually slow because of code-folding... ActiveDoc.Highlighter := frmMain.sciEditor.LanguageManager.SelectedLanguage; ActiveDoc.ReadOnly := frmMain.sciEditor.ReadOnly; ActiveDoc.SelStart := frmMain.sciEditor.SelStart; ActiveDoc.SelLength := frmMain.sciEditor.SelLength; ActiveDoc.TopLine := frmMain.sciEditor.GetFirstVisibleLine; ActiveDoc.Modified := frmMain.sciEditor.Modified; ActiveDoc.NotesText := GetRTFText(frmMain.rtfNotes); end; Screen.Cursor := crHourGlass; Cancel := False; ShowProgress(True); AssignFile(F, AFilename); { ... count lines ... } i := 0; Reset(F); while not EOF(F) do begin ReadLn(F, eString); Inc(i, 1); end; { ... read lines ... } Reset(F); with Add(AFilename, AHighlighter) do begin ShowProgress(True); frmMain.pbLoading.Max := i; i := 0; while not EOF(F) do begin if Cancel then begin Cancel := False; CloseFile(F); exit; end; ReadLn(F, eString); if Assigned(GetCurrLang(AFilename)) then begin if (eString = GetCurrLang(AFilename).CommentBoxStart + ' AMXX-Studio Notes - DO NOT MODIFY BELOW HERE') and (frmSettings.optFileComment.Checked) then begin try ReadLn(F, eString); eString := Copy(eString, Length(GetCurrLang(AFilename).CommentBoxMiddle) +1, Length(eString)); NotesText := eString; ReadLn(F, eString); except MessageBox(frmMain.Handle, PChar(lFailedLoadNotes), PChar(Application.Title), MB_ICONERROR); end; end else begin if i = 0 then Code := eString else Code := Code + #13#10 + eString; end; end else begin if i = 0 then Code := eString else Code := Code + #13#10 + eString; end; frmMain.pbLoading.Position := i; SetProgressStatus('Loading file...'); Inc(i, 1); Application.ProcessMessages; end; HideProgress; Result := Index; CloseFile(F); if frmSettings.optConfig.Checked then begin eLines := TStringList.Create; if FileExists(ExtractFilePath(ParamStr(0)) + 'config\Notes.dat') then eLines.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'config\Notes.dat') else begin eLines.Clear; // something must be wrong, clear eLines.Add('AMXX-Studio Notes - DO NOT MODIFY THIS FILE'); eLines.SaveToFile(ExtractFilePath(ParamStr(0)) + 'config\Notes.dat'); end; i := 0; // line 1 is a comment while i < eLines.Count -1 do begin Inc(i, 2); if LowerCase(FFilename) = LowerCase(eLines[i -1]) then begin NotesText := eLines[i]; break; end; end; eLines.Destroy; end; end; Screen.Cursor := crDefault; if not Plugin_FileLoad(AFilename, False) then exit; if Result <> -1 then Activate(Result, False); end; function TDocCollection.Save(AIndex: Integer; AFilename: String): Boolean; begin if AFilename <> '' then TDocument(Items[AIndex]).FileName := AFileName; Result := TDocument(Items[AIndex]).Save; end; procedure mIRCDDE(Service, Topic, Cmd: string); var DDE: TDDEClientConv; begin DDE := TDDEClientConv.Create(nil); try DDE.SetLink(Service, Topic); DDE.OpenLink; DDE.PokeData(Topic, PChar(Cmd)); finally DDE.Free; end; end; function mIRCGet(Service, Topic, Item: string): String; var DDE: TDDEClientConv; begin DDE := TDDEClientConv.Create(nil); try DDE.SetLink(Service, Topic); Result := DDE.RequestData(Item); finally DDE.Free; end; end; function GetAllDirs: TStringList; var eList: TStringList; i: integer; begin eList := TStringList.Create; frmMain.IdFTP.List(eList); frmMain.IdFTP.DirectoryListing.LoadList(eList); eList.Clear; for i := 0 to frmMain.IdFTP.DirectoryListing.Count -1 do begin if frmMain.IdFTP.DirectoryListing.Items[i].ItemType = ditDirectory then eList.Add(frmMain.IdFTP.DirectoryListing.Items[i].FileName); end; Result := eList; end; procedure SetProxySettings; begin with frmMain.IdFTP.ProxySettings do begin case frmSettings.cboProxy.ItemIndex of 0: ProxyType := fpcmNone; // none 1: ProxyType := fpcmHttpProxyWithFtp; // HTTP Proxy with FTP 2: ProxyType := fpcmOpen; // Open 3: ProxyType := fpcmSite; // Site 4: ProxyType := fpcmTransparent; // Transparent 5: ProxyType := fpcmUserPass; // User (Password) 6: ProxyType := fpcmUserSite; // User (Site) end; Host := frmSettings.txtProxyHost.Text; Port := StrToInt(frmSettings.txtProxyPort.Text); Username := frmSettings.txtProxyUsername.Text; Password := frmSettings.txtProxyPassword.Text; end; end; function TryConnect: Integer; begin Result := 0; frmMain.IdFTP.Host := frmSettings.txtHost.Text; frmMain.IdFTP.Port := StrToInt(frmSettings.txtPort.Text); frmMain.IdFTP.Username := frmSettings.txtUsername.Text; frmMain.IdFTP.Passive := frmSettings.chkPassive.Checked; frmMain.IdFTP.Password := frmSettings.txtPassword.Text; SetProxySettings; try frmMain.IdFTP.Connect(True, 15000); except on E: Exception do begin if Pos('Login incorrect.', E.Message) <> 0 then begin // login failed MessageBox(Application.Handle, PChar(lLoginIncorrect), PChar(Application.Title), MB_ICONWARNING); Result := 1; end else if Pos('Host not found.', E.Message) <> 0 then begin // host not found MessageBox(Application.Handle, PChar(lHostNotFound), PChar(Application.Title), MB_ICONWARNING); Result := 2; end else if Pos('Connection refused.', E.Message) <> 0 then begin // wrong port (?) MessageBox(Application.Handle, PChar(lConnectionRefused), PChar(Application.Title), MB_ICONWARNING); Result := 3; end else if E is EIdProtocolReplyError then begin // wrong port MessageBox(Application.Handle, PChar(lWrongPort), PChar(Application.Title), MB_ICONWARNING); Result := 4; end else begin MessageBox(Application.Handle, PChar(E.Message), PChar(Application.Title), MB_ICONWARNING); // unknown error Result := 5; end; end; end; end; { Initialization & Finalization } initialization PawnProjects := TDocCollection.Create('Pawn'); CPPProjects := TDocCollection.Create('C++'); OtherProjects := TDocCollection.Create('null'); CurrProjects := 0; ActiveDoc := PawnProjects.ActiveDocument; finalization PawnProjects.Free; CPPProjects.Free; OtherProjects.Free; end.