mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-26 22:23:49 +02:00
18550 lines
638 KiB
ObjectPascal
18550 lines
638 KiB
ObjectPascal
{
|
|
/***************************************************************************
|
|
main.pp - the "integrated" in IDE
|
|
-----------------------------------
|
|
TMainIDE is the main controlling and instance of the IDE, which connects the
|
|
various parts of the IDE.
|
|
|
|
main.pp - TMainIDE = class(TMainIDEBase)
|
|
The highest manager/boss of the IDE. Only lazarus.pp uses
|
|
this unit.
|
|
mainbase.pas - TMainIDEBase = class(TMainIDEInterface)
|
|
The ancestor class used by (and only by) the other
|
|
bosses/managers like debugmanager, pkgmanager.
|
|
mainintf.pas - TMainIDEInterface = class(TLazIDEInterface)
|
|
The interface class of the top level functions of the IDE.
|
|
TMainIDEInterface is used by functions/units, that uses
|
|
several different parts of the IDE (designer, source editor,
|
|
codetools), so they can't be added to a specific boss and
|
|
which are yet too small to become a boss of their own.
|
|
lazideintf.pas - TLazIDEInterface = class(TComponent)
|
|
For designtime packages, this is the interface class of the
|
|
top level functions of the IDE.
|
|
|
|
|
|
Initial Revision : Sun Mar 28 23:15:32 CST 1999
|
|
|
|
|
|
***************************************************************************/
|
|
|
|
***************************************************************************
|
|
* *
|
|
* This source is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This code is distributed in the hope that it will be useful, but *
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
* General Public License for more details. *
|
|
* *
|
|
* A copy of the GNU General Public License is available on the World *
|
|
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
|
|
* obtain it by writing to the Free Software Foundation, *
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
* *
|
|
***************************************************************************
|
|
}
|
|
unit Main;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
{$I ide.inc}
|
|
|
|
uses
|
|
{$IFDEF IDE_MEM_CHECK}
|
|
MemCheck,
|
|
{$ENDIF}
|
|
// fpc packages
|
|
Math, Classes, SysUtils, Process, AsyncProcess, TypInfo, types, AVL_Tree,
|
|
// lcl
|
|
LCLProc, LCLMemManager, LCLType, LCLIntf, LConvEncoding, LMessages, ComCtrls,
|
|
FileUtil, LResources, StdCtrls, Forms, Buttons, Menus, Controls, GraphType,
|
|
HelpIntfs, Graphics, ExtCtrls, Dialogs, InterfaceBase, UTF8Process,
|
|
//
|
|
LazUTF8,
|
|
// codetools
|
|
FileProcs, CodeBeautifier, FindDeclarationTool, LinkScanner, BasicCodeTools,
|
|
Laz_XMLCfg, CodeToolsStructs, CodeToolManager, CodeCache, DefineTemplates,
|
|
KeywordFuncLists,
|
|
// synedit
|
|
AllSynEdit, SynEditKeyCmds, SynBeautifier, SynEditMarks,
|
|
// IDE interface
|
|
IDEIntf, BaseIDEIntf, ObjectInspector, PropEdits, PropEditUtils,
|
|
MacroIntf, IDECommands, IDEWindowIntf,
|
|
SrcEditorIntf, NewItemIntf, IDEExternToolIntf, IDEMsgIntf,
|
|
PackageIntf, ProjectIntf, CompOptsIntf, MenuIntf, LazIDEIntf, IDEDialogs,
|
|
IDEOptionsIntf, IDEImagesIntf,
|
|
// protocol
|
|
IDEProtocol,
|
|
// compile
|
|
Compiler, CompilerOptions, CheckCompilerOpts, BuildProjectDlg,
|
|
ApplicationBundle, ImExportCompilerOpts, InfoBuild,
|
|
// projects
|
|
ProjectResources, Project, ProjectDefs, NewProjectDlg,
|
|
PublishProjectDlg, ProjectInspector, PackageDefs,
|
|
// help manager
|
|
IDEContextHelpEdit, IDEHelpIntf, IDEHelpManager, CodeHelp, HelpOptions,
|
|
// designer
|
|
JITForms, ComponentPalette, ComponentList, ComponentReg, FormEditingIntf,
|
|
ObjInspExt, Designer, FormEditor, CustomFormEditor,
|
|
ControlSelection, AnchorEditor, TabOrderDlg, MenuEditorForm,
|
|
// LRT stuff
|
|
Translations,
|
|
// debugger
|
|
RunParamsOpts, BaseDebugManager, DebugManager, debugger, DebuggerDlg,
|
|
// packager
|
|
PackageSystem, PkgManager, BasePkgManager,
|
|
// source editing
|
|
SourceEditor, CodeToolsOptions, IDEOptionDefs, CheckLFMDlg,
|
|
CodeToolsDefines, DiffDialog, DiskDiffsDialog, UnitInfoDlg, EditorOptions,
|
|
SourceEditProcs, MsgQuickFixes, ViewUnit_dlg, FPDocEditWindow,
|
|
// converter
|
|
ChgEncodingDlg, ConvertDelphi, MissingPropertiesDlg, LazXMLForms,
|
|
// environment option frames
|
|
editor_general_options, formed_options, OI_options,
|
|
files_options, desktop_options, window_options,
|
|
Backup_Options, naming_options, fpdoc_options,
|
|
editor_display_options, editor_keymapping_options, editor_mouseaction_options,
|
|
editor_mouseaction_options_advanced, editor_color_options, editor_markup_options,
|
|
editor_codetools_options, editor_codefolding_options,
|
|
editor_general_misc_options, editor_dividerdraw_options,
|
|
editor_multiwindow_options,
|
|
codetools_general_options, codetools_codecreation_options,
|
|
codetools_classcompletion_options, atom_checkboxes_options,
|
|
codetools_wordpolicy_options, codetools_linesplitting_options,
|
|
codetools_space_options, codetools_identifiercompletion_options,
|
|
debugger_general_options, debugger_eventlog_options,
|
|
debugger_language_exceptions_options, debugger_signals_options,
|
|
codeexplorer_update_options, codeexplorer_categories_options,
|
|
codeobserver_options,
|
|
help_general_options,
|
|
// project option frames
|
|
project_application_options, project_forms_options, project_lazdoc_options,
|
|
project_save_options, project_versioninfo_options, project_i18n_options,
|
|
project_misc_options,
|
|
// project compiler option frames
|
|
compiler_path_options, compiler_parsing_options, compiler_codegen_options,
|
|
compiler_linking_options, compiler_verbosity_options, compiler_messages_options,
|
|
compiler_other_options, compiler_inherited_options, compiler_compilation_options,
|
|
BuildModesEditor, compiler_buildmacro_options,
|
|
// package option frames
|
|
package_usage_options, package_description_options, package_integration_options,
|
|
package_provides_options, package_i18n_options,
|
|
|
|
// rest of the ide
|
|
Splash, IDEDefs, LazarusIDEStrConsts, LazConf, MsgView, SearchResultView,
|
|
CodeTemplatesDlg, CodeBrowser, FindUnitDlg, InspectChksumChangedDlg,
|
|
IdeOptionsDlg, EditDefineTree, PublishModule, EnvironmentOpts, TransferMacros,
|
|
KeyMapping, IDETranslations, IDEProcs, ExtToolDialog, ExtToolEditDlg,
|
|
OutputFilter, JumpHistoryView, ManageExamples,
|
|
BuildLazDialog, BuildProfileManager, BuildManager, CheckCompOptsForNewUnitDlg,
|
|
MiscOptions, InputHistory, UnitDependencies, ClipBoardHistory,
|
|
IDEFPCInfo, IDEInfoDlg, ProcessList, InitialSetupDlgs, NewDialog,
|
|
MakeResStrDlg, DialogProcs, FindReplaceDialog, FindInFilesDlg, CodeExplorer,
|
|
BuildFileDlg, ProcedureList, ExtractProcDlg, FindRenameIdentifier,
|
|
AbstractsMethodsDlg, EmptyMethodsDlg, UnusedUnitsDlg, UseUnitDlg, FindOverloadsDlg,
|
|
CleanDirDlg, CodeContextForm, AboutFrm, CompatibilityRestrictions,
|
|
RestrictionBrowser, ProjectWizardDlg, IDECmdLine, IDEGuiCmdLine, CodeExplOpts,
|
|
// main ide
|
|
MainBar, MainIntf, MainBase;
|
|
|
|
type
|
|
TIDEProjectItem =
|
|
(
|
|
piUnit,
|
|
piComponent,
|
|
piFrame
|
|
);
|
|
|
|
TIDECodetoolsDefines = (
|
|
ctdReady,
|
|
ctdNeedUpdate,
|
|
ctdUpdating
|
|
);
|
|
|
|
{ TMainIDE }
|
|
|
|
TMainIDE = class(TMainIDEBase)
|
|
// event handlers
|
|
procedure MainIDEFormClose(Sender: TObject; var CloseAction: TCloseAction);
|
|
procedure MainIDEFormCloseQuery(Sender: TObject; var CanClose: boolean);
|
|
procedure OnApplicationUserInput(Sender: TObject; Msg: Cardinal);
|
|
procedure OnApplicationIdle(Sender: TObject; var Done: Boolean);
|
|
procedure OnApplicationActivate(Sender: TObject);
|
|
procedure OnApplicationDeActivate(Sender: TObject);
|
|
procedure OnApplicationKeyDown(Sender: TObject;
|
|
var Key: Word; Shift: TShiftState);
|
|
procedure OnApplicationDropFiles(Sender: TObject; const FileNames: array of String);
|
|
procedure OnApplicationQueryEndSession(var Cancel: Boolean);
|
|
procedure OnApplicationEndSession(Sender: TObject);
|
|
procedure OnScreenRemoveForm(Sender: TObject; AForm: TCustomForm);
|
|
procedure OnRemoteControlTimer(Sender: TObject);
|
|
procedure OnSelectFrame(Sender: TObject; var AComponentClass: TComponentClass);
|
|
procedure OIChangedTimerTimer(Sender: TObject);
|
|
procedure OnMainBarActive(Sender: TObject);
|
|
|
|
// file menu
|
|
procedure mnuFileClicked(Sender: TObject);
|
|
procedure mnuNewUnitClicked(Sender: TObject);
|
|
procedure mnuNewFormClicked(Sender: TObject);
|
|
procedure mnuNewOtherClicked(Sender: TObject);
|
|
procedure mnuOpenClicked(Sender: TObject);
|
|
procedure mnuOpenRecentClicked(Sender: TObject);
|
|
procedure mnuRevertClicked(Sender: TObject);
|
|
procedure mnuSaveClicked(Sender: TObject);
|
|
procedure mnuSaveAsClicked(Sender: TObject);
|
|
procedure mnuSaveAllClicked(Sender: TObject);
|
|
procedure mnuCloseClicked(Sender: TObject);
|
|
procedure mnuCloseAllClicked(Sender: TObject);
|
|
procedure mnuCleanDirectoryClicked(Sender: TObject);
|
|
procedure mnuRestartClicked(Sender: TObject);
|
|
procedure mnuQuitClicked(Sender: TObject);
|
|
|
|
// edit menu
|
|
procedure mnuEditClicked(Sender: TObject);
|
|
procedure mnuEditUndoClicked(Sender: TObject);
|
|
procedure mnuEditRedoClicked(Sender: TObject);
|
|
procedure mnuEditCutClicked(Sender: TObject);
|
|
procedure mnuEditCopyClicked(Sender: TObject);
|
|
procedure mnuEditPasteClicked(Sender: TObject);
|
|
procedure mnuEditSelectAllClick(Sender: TObject);
|
|
procedure mnuEditSelectCodeBlockClick(Sender: TObject);
|
|
procedure mnuEditSelectToBraceClick(Sender: TObject);
|
|
procedure mnuEditSelectWordClick(Sender: TObject);
|
|
procedure mnuEditSelectLineClick(Sender: TObject);
|
|
procedure mnuEditSelectParagraphClick(Sender: TObject);
|
|
procedure mnuEditUpperCaseBlockClicked(Sender: TObject);
|
|
procedure mnuEditLowerCaseBlockClicked(Sender: TObject);
|
|
procedure mnuEditSwapCaseBlockClicked(Sender: TObject);
|
|
procedure mnuEditIndentBlockClicked(Sender: TObject);
|
|
procedure mnuEditUnindentBlockClicked(Sender: TObject);
|
|
procedure mnuEditSortBlockClicked(Sender: TObject);
|
|
procedure mnuEditTabsToSpacesBlockClicked(Sender: TObject);
|
|
procedure mnuEditSelectionBreakLinesClicked(Sender: TObject);
|
|
procedure mnuEditInsertCharacterClicked(Sender: TObject);
|
|
|
|
// search menu
|
|
procedure mnuSearchFindInFiles(Sender: TObject);
|
|
procedure mnuSearchFindIdentifierRefsClicked(Sender: TObject);
|
|
procedure mnuSearchFindBlockOtherEnd(Sender: TObject);
|
|
procedure mnuSearchFindBlockStart(Sender: TObject);
|
|
procedure mnuSearchFindDeclaration(Sender: TObject);
|
|
procedure mnuFindDeclarationClicked(Sender: TObject);
|
|
procedure mnuOpenFileAtCursorClicked(Sender: TObject);
|
|
procedure mnuGotoIncludeDirectiveClicked(Sender: TObject);
|
|
procedure mnuSearchProcedureList(Sender: TObject);
|
|
procedure mnuSetFreeBookmark(Sender: TObject);
|
|
|
|
// view menu
|
|
procedure mnuViewInspectorClicked(Sender: TObject);
|
|
procedure mnuViewSourceEditorClicked(Sender: TObject);
|
|
procedure mnuViewUnitDependenciesClicked(Sender: TObject);
|
|
procedure mnuViewFPDocEditorClicked(Sender: TObject);
|
|
procedure mnuViewCodeExplorerClick(Sender: TObject);
|
|
procedure mnuViewCodeBrowserClick(Sender: TObject);
|
|
procedure mnuViewComponentsClick(Sender: TObject);
|
|
procedure mnuViewRestrictionBrowserClick(Sender: TObject);
|
|
procedure mnuViewMessagesClick(Sender: TObject);
|
|
procedure mnuViewSearchResultsClick(Sender: TObject);
|
|
procedure mnuToggleFormUnitClicked(Sender: TObject);
|
|
procedure mnuViewAnchorEditorClicked(Sender: TObject);
|
|
procedure mnuViewTabOrderClicked(Sender: TObject);
|
|
procedure mnuViewComponentPaletteClicked(Sender: TObject);
|
|
procedure mnuViewIDESpeedButtonsClicked(Sender: TObject);
|
|
procedure mnuViewFPCInfoClicked(Sender: TObject);
|
|
procedure mnuViewIDEInfoClicked(Sender: TObject);
|
|
|
|
// source menu
|
|
procedure mnuSourceClicked(Sender: TObject);
|
|
procedure mnuSourceCommentBlockClicked(Sender: TObject);
|
|
procedure mnuSourceUncommentBlockClicked(Sender: TObject);
|
|
procedure mnuSourceToggleCommentClicked(Sender: TObject);
|
|
procedure mnuSourceEncloseBlockClicked(Sender: TObject);
|
|
procedure mnuSourceEncloseInIFDEFClicked(Sender: TObject);
|
|
procedure mnuSourceCompleteCodeClicked(Sender: TObject);
|
|
procedure mnuSourceUseUnitClicked(Sender: TObject);
|
|
procedure mnuSourceSyntaxCheckClicked(Sender: TObject);
|
|
procedure mnuSourceGuessUnclosedBlockClicked(Sender: TObject);
|
|
procedure mnuSourceGuessMisplacedIFDEFClicked(Sender: TObject);
|
|
// source->insert CVS keyword
|
|
procedure mnuSourceInsertCVSAuthorClick(Sender: TObject);
|
|
procedure mnuSourceInsertCVSDateClick(Sender: TObject);
|
|
procedure mnuSourceInsertCVSHeaderClick(Sender: TObject);
|
|
procedure mnuSourceInsertCVSIDClick(Sender: TObject);
|
|
procedure mnuSourceInsertCVSLogClick(Sender: TObject);
|
|
procedure mnuSourceInsertCVSNameClick(Sender: TObject);
|
|
procedure mnuSourceInsertCVSRevisionClick(Sender: TObject);
|
|
procedure mnuSourceInsertCVSSourceClick(Sender: TObject);
|
|
// source->insert general
|
|
procedure mnuSourceInsertGPLNoticeClick(Sender: TObject);
|
|
procedure mnuSourceInsertLGPLNoticeClick(Sender: TObject);
|
|
procedure mnuSourceInsertModifiedLGPLNoticeClick(Sender: TObject);
|
|
procedure mnuSourceInsertUsernameClick(Sender: TObject);
|
|
procedure mnuSourceInsertDateTimeClick(Sender: TObject);
|
|
procedure mnuSourceInsertChangeLogEntryClick(Sender: TObject);
|
|
procedure mnuSourceInsertGUID(Sender: TObject);
|
|
// source->insert full Filename
|
|
procedure mnuSourceInsertFilename(Sender: TObject);
|
|
// source->Tools
|
|
procedure mnuSourceUnitInfoClicked(Sender: TObject);
|
|
|
|
// refactor menu
|
|
procedure mnuRefactorRenameIdentifierClicked(Sender: TObject);
|
|
procedure mnuRefactorExtractProcClicked(Sender: TObject);
|
|
procedure mnuRefactorInvertAssignmentClicked(Sender: TObject);
|
|
procedure mnuRefactorShowAbstractMethodsClicked(Sender: TObject);
|
|
procedure mnuRefactorShowEmptyMethodsClicked(Sender: TObject);
|
|
procedure mnuRefactorShowUnusedUnitsClicked(Sender: TObject);
|
|
procedure mnuRefactorFindOverloadsClicked(Sender: TObject);
|
|
procedure mnuRefactorMakeResourceStringClicked(Sender: TObject);
|
|
|
|
// project menu
|
|
procedure mnuNewProjectClicked(Sender: TObject);
|
|
procedure mnuNewProjectFromFileClicked(Sender: TObject);
|
|
procedure mnuOpenProjectClicked(Sender: TObject);
|
|
procedure mnuCloseProjectClicked(Sender: TObject);
|
|
procedure mnuSaveProjectClicked(Sender: TObject);
|
|
procedure mnuSaveProjectAsClicked(Sender: TObject);
|
|
procedure mnuPublishProjectClicked(Sender: TObject);
|
|
procedure mnuProjectInspectorClicked(Sender: TObject);
|
|
procedure mnuAddToProjectClicked(Sender: TObject);
|
|
procedure mnuRemoveFromProjectClicked(Sender: TObject);
|
|
procedure mnuViewUnitsClicked(Sender: TObject);
|
|
procedure mnuViewFormsClicked(Sender: TObject);
|
|
procedure mnuViewProjectSourceClicked(Sender: TObject);
|
|
procedure mnuProjectOptionsClicked(Sender: TObject);
|
|
|
|
// run menu
|
|
procedure mnuCompileProjectClicked(Sender: TObject);
|
|
procedure mnuBuildProjectClicked(Sender: TObject);
|
|
procedure mnuQuickCompileProjectClicked(Sender: TObject);
|
|
procedure mnuCleanUpCompiledProjectClicked(Sender: TObject);
|
|
procedure mnuAbortBuildProjectClicked(Sender: TObject);
|
|
procedure mnuRunProjectClicked(Sender: TObject);
|
|
procedure mnuPauseProjectClicked(Sender: TObject);
|
|
procedure mnuShowExecutionPointClicked(Sender: TObject);
|
|
procedure mnuStepIntoProjectClicked(Sender: TObject);
|
|
procedure mnuStepOverProjectClicked(Sender: TObject);
|
|
procedure mnuStepIntoInstrProjectClicked(Sender: TObject);
|
|
procedure mnuStepOverInstrProjectClicked(Sender: TObject);
|
|
procedure mnuStepOutProjectClicked(Sender: TObject);
|
|
procedure mnuRunToCursorProjectClicked(Sender: TObject);
|
|
procedure mnuStopProjectClicked(Sender: TObject);
|
|
procedure mnuRunParametersClicked(Sender: TObject);
|
|
procedure mnuBuildFileClicked(Sender: TObject);
|
|
procedure mnuRunFileClicked(Sender: TObject);
|
|
procedure mnuConfigBuildFileClicked(Sender: TObject);
|
|
|
|
// project menu
|
|
procedure mnuProjectClicked(Sender: TObject);
|
|
|
|
// package menu
|
|
procedure mnuPackageClicked(Sender: TObject);
|
|
// see pkgmanager.pas
|
|
|
|
// tools menu
|
|
procedure mnuToolConfigureClicked(Sender: TObject);
|
|
procedure mnuToolDiffClicked(Sender: TObject);
|
|
procedure mnuToolConvertDFMtoLFMClicked(Sender: TObject);
|
|
procedure mnuToolCheckLFMClicked(Sender: TObject);
|
|
procedure mnuToolConvertDelphiUnitClicked(Sender: TObject);
|
|
procedure mnuToolConvertDelphiProjectClicked(Sender: TObject);
|
|
procedure mnuToolConvertDelphiPackageClicked(Sender: TObject);
|
|
procedure mnuToolConvertEncodingClicked(Sender: TObject);
|
|
procedure mnuToolManageExamplesClicked(Sender: TObject);
|
|
procedure mnuToolBuildLazarusClicked(Sender: TObject);
|
|
procedure mnuToolBuildAdvancedLazarusClicked(Sender: TObject);
|
|
procedure mnuToolConfigBuildLazClicked(Sender: TObject);
|
|
procedure mnuCustomExtToolClick(Sender: TObject);
|
|
|
|
// environment menu
|
|
procedure mnuEnvGeneralOptionsClicked(Sender: TObject);
|
|
procedure mnuEnvEditorOptionsClicked(Sender: TObject);
|
|
procedure mnuEnvCodeTemplatesClicked(Sender: TObject);
|
|
procedure mnuEnvCodeToolsDefinesEditorClicked(Sender: TObject);
|
|
procedure mnuEnvRescanFPCSrcDirClicked(Sender: TObject);
|
|
|
|
// windows menu
|
|
|
|
// help menu
|
|
// see helpmanager.pas
|
|
|
|
procedure OpenFilePopupMenuPopup(Sender: TObject);
|
|
procedure mnuOpenFilePopupClick(Sender: TObject);
|
|
procedure SetBuildModePopupMenuPopup(Sender: TObject);
|
|
procedure mnuChgBuildModeClicked(Sender: TObject);
|
|
procedure mnuSetBuildModeClick(Sender: TObject); // event for drop down items
|
|
private
|
|
function DoBuildLazarusSub(Flags: TBuildLazarusFlags): TModalResult;
|
|
function ExternalTools: TExternalToolList;
|
|
public
|
|
// Global IDE events
|
|
procedure OnProcessIDECommand(Sender: TObject; Command: word;
|
|
var Handled: boolean);
|
|
procedure OnExecuteIDEShortCut(Sender: TObject;
|
|
var Key: word; Shift: TShiftState;
|
|
IDEWindowClass: TCustomFormClass);
|
|
function OnExecuteIDECommand(Sender: TObject; Command: word): boolean;
|
|
function OnSelectDirectory(const Title, InitialDir: string): string;
|
|
procedure OnInitIDEFileDialog(AFileDialog: TFileDialog);
|
|
procedure OnStoreIDEFileDialog(AFileDialog: TFileDialog);
|
|
function OnIDEMessageDialog(const aCaption, aMsg: string;
|
|
DlgType: TMsgDlgType; Buttons: TMsgDlgButtons;
|
|
const HelpKeyword: string): Integer;
|
|
function OnIDEQuestionDialog(const aCaption, aMsg: string;
|
|
DlgType: TMsgDlgType; Buttons: array of const;
|
|
const HelpKeyword: string): Integer;
|
|
|
|
// Environment options dialog events
|
|
procedure OnLoadIDEOptions(Sender: TObject; AOptions: TAbstractIDEOptions);
|
|
procedure OnSaveIDEOptions(Sender: TObject; AOptions: TAbstractIDEOptions);
|
|
procedure DoOpenIDEOptions(AEditor: TAbstractIDEOptionsEditorClass;
|
|
ACaption: String;
|
|
AOptionsFilter: array of TAbstractIDEOptionsClass;
|
|
ASettings: TIDEOptionsEditorSettings); override;
|
|
|
|
procedure DoEnvironmentOptionsBeforeRead(Sender: TObject);
|
|
procedure DoEnvironmentOptionsBeforeWrite(Sender: TObject; Restore: boolean);
|
|
procedure DoEnvironmentOptionsAfterWrite(Sender: TObject; Restore: boolean);
|
|
procedure DoEditorOptionsBeforeRead(Sender: TObject);
|
|
procedure DoEditorOptionsAfterWrite(Sender: TObject; Restore: boolean);
|
|
procedure DoCodetoolsOptionsAfterWrite(Sender: TObject; Restore: boolean);
|
|
procedure DoCodeExplorerOptionsAfterWrite(Sender: TObject; Restore: boolean);
|
|
procedure DoProjectOptionsBeforeRead(Sender: TObject);
|
|
procedure DoProjectOptionsAfterWrite(Sender: TObject; Restore: boolean);
|
|
|
|
// ComponentPalette events
|
|
procedure ComponentPaletteClassSelected(Sender: TObject);
|
|
|
|
// SourceNotebook events
|
|
procedure OnSrcNoteBookActivated(Sender: TObject);
|
|
procedure OnSrcNoteBookAddJumpPoint(ACaretXY: TPoint; ATopLine: integer;
|
|
AEditor: TSourceEditor; DeleteForwardHistory: boolean);
|
|
procedure OnSrcNoteBookClickLink(Sender: TObject;
|
|
Button: TMouseButton; Shift: TShiftstate; X, Y: Integer);
|
|
procedure OnSrcNoteBookMouseLink(
|
|
Sender: TObject; X, Y: Integer; var AllowMouseLink: Boolean);
|
|
function OnSrcNoteBookGetIndent(Sender: TObject; SrcEditor: TSourceEditor;
|
|
LogCaret, OldLogCaret: TPoint; FirstLinePos, LastLinePos: Integer;
|
|
Reason: TSynEditorCommand; SetIndentProc: TSynBeautifierSetIndentProc): Boolean;
|
|
procedure OnSrcNotebookDeleteLastJumPoint(Sender: TObject);
|
|
procedure OnSrcNotebookEditorActived(Sender: TObject);
|
|
procedure OnSrcNotebookEditorPlaceBookmark(Sender: TObject; var Mark: TSynEditMark);
|
|
procedure OnSrcNotebookEditorClearBookmark(Sender: TObject; var Mark: TSynEditMark);
|
|
procedure OnSrcNotebookEditorDoSetBookmark(Sender: TObject; ID: Integer; Toggle: Boolean);
|
|
procedure OnSrcNotebookEditorDoGotoBookmark(Sender: TObject; ID: Integer; Backward: Boolean);
|
|
procedure OnSrcNotebookEditorChanged(Sender: TObject);
|
|
procedure OnSrcNotebookEditorMoved(Sender: TObject);
|
|
procedure OnSrcNotebookEditorClosed(Sender: TObject);
|
|
procedure OnSrcNotebookCurCodeBufferChanged(Sender: TObject);
|
|
procedure OnSrcNotebookFileNew(Sender: TObject);
|
|
procedure OnSrcNotebookFileOpen(Sender: TObject);
|
|
procedure OnSrcNotebookFileOpenAtCursor(Sender: TObject);
|
|
procedure OnSrcNotebookFileSave(Sender: TObject);
|
|
procedure OnSrcNotebookFileSaveAs(Sender: TObject);
|
|
procedure OnSrcNotebookFileClose(Sender: TObject; InvertedClose: boolean);
|
|
procedure OnSrcNotebookFindDeclaration(Sender: TObject);
|
|
procedure OnSrcNotebookInitIdentCompletion(Sender: TObject;
|
|
JumpToError: boolean; out Handled, Abort: boolean);
|
|
procedure OnSrcNotebookShowCodeContext(JumpToError: boolean;
|
|
out Abort: boolean);
|
|
procedure OnSrcNotebookJumpToHistoryPoint(var NewCaretXY: TPoint;
|
|
var NewTopLine: integer; var DestEditor: TSourceEditor; JumpAction: TJumpHistoryAction);
|
|
procedure OnSrcNotebookReadOnlyChanged(Sender: TObject);
|
|
procedure OnSrcNotebookSaveAll(Sender: TObject);
|
|
procedure OnSrcNotebookShowHintForSource(SrcEdit: TSourceEditor;
|
|
ClientPos: TPoint; CaretPos: TPoint);
|
|
procedure OnSrcNoteBookShowUnitInfo(Sender: TObject);
|
|
procedure OnSrcNotebookToggleFormUnit(Sender: TObject);
|
|
procedure OnSrcNotebookToggleObjectInsp(Sender: TObject);
|
|
procedure OnSrcNotebookViewJumpHistory(Sender: TObject);
|
|
procedure OnSrcNoteBookPopupMenu(const AddMenuItemProc: TAddMenuItemProc);
|
|
procedure OnSrcNoteBookCloseQuery(Sender: TObject; var CloseAction: TCloseAction);
|
|
|
|
// ObjectInspector + PropertyEditorHook events
|
|
procedure OIOnSelectPersistents(Sender: TObject);
|
|
procedure OIOnShowOptions(Sender: TObject);
|
|
procedure OIOnViewRestricted(Sender: TObject);
|
|
procedure OIOnDestroy(Sender: TObject);
|
|
procedure OIOnAutoShow(Sender: TObject);
|
|
procedure OIRemainingKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
procedure OIOnAddToFavourites(Sender: TObject);
|
|
procedure OIOnRemoveFromFavourites(Sender: TObject);
|
|
procedure OIOnFindDeclarationOfProperty(Sender: TObject);
|
|
procedure OIOnSelectionChange(Sender: TObject);
|
|
function OIOnPropertyHint(Sender: TObject; PointedRow: TOIPropertyGridRow;
|
|
ScreenPos: TPoint; aHintWindow: THintWindow;
|
|
out HintWinRect: TRect; out AHint: string): boolean;
|
|
procedure OIOnUpdateRestricted(Sender: TObject);
|
|
function OnPropHookGetMethodName(const Method: TMethod;
|
|
PropOwner: TObject): String;
|
|
procedure OnPropHookGetMethods(TypeData: PTypeData; Proc:TGetStrProc);
|
|
procedure OnPropHookGetCompatibleMethods(InstProp: PInstProp;
|
|
const Proc:TGetStrProc);
|
|
function OnPropHookCompatibleMethodExists(const AMethodName: String;
|
|
InstProp: PInstProp;
|
|
var MethodIsCompatible, MethodIsPublished,
|
|
IdentIsMethod: boolean): boolean;
|
|
function OnPropHookMethodExists(const AMethodName: String;
|
|
TypeData: PTypeData;
|
|
var MethodIsCompatible, MethodIsPublished,
|
|
IdentIsMethod: boolean): boolean;
|
|
function OnPropHookCreateMethod(const AMethodName:ShortString;
|
|
ATypeInfo:PTypeInfo;
|
|
APersistent: TPersistent;
|
|
const APropertyPath: string): TMethod;
|
|
procedure OnPropHookShowMethod(const AMethodName: String);
|
|
procedure OnPropHookRenameMethod(const CurName, NewName: String);
|
|
function OnPropHookBeforeAddPersistent(Sender: TObject;
|
|
APersistentClass: TPersistentClass;
|
|
AParent: TPersistent): boolean;
|
|
procedure OnPropHookComponentRenamed(AComponent: TComponent);
|
|
procedure OnPropHookModified(Sender: TObject);
|
|
procedure OnPropHookPersistentAdded(APersistent: TPersistent;
|
|
Select: boolean);
|
|
procedure OnPropHookPersistentDeleting(APersistent: TPersistent);
|
|
procedure OnPropHookDeletePersistent(var APersistent: TPersistent);
|
|
procedure OnPropHookObjectPropertyChanged(Sender: TObject;
|
|
NewObject: TPersistent);
|
|
procedure OnPropHookAddDependency(const AClass: TClass;
|
|
const AnUnitName: shortstring);
|
|
procedure OnPropHookGetComponentNames(TypeData: PTypeData;
|
|
Proc: TGetStrProc);
|
|
function OnPropHookGetComponent(const ComponentPath: String): TComponent;
|
|
|
|
// designer events
|
|
procedure OnDesignerGetSelectedComponentClass(Sender: TObject;
|
|
var RegisteredComponent: TRegisteredComponent);
|
|
procedure OnDesignerComponentAdded(Sender: TObject);
|
|
procedure OnDesignerSetDesigning(Sender: TObject; Component: TComponent;
|
|
Value: boolean);
|
|
procedure OnDesignerShowOptions(Sender: TObject);
|
|
procedure OnDesignerPasteComponent(Sender: TObject; LookupRoot: TComponent;
|
|
TxtCompStream: TStream; ParentControl: TWinControl;
|
|
var NewComponent: TComponent);
|
|
procedure OnDesignerPropertiesChanged(Sender: TObject);
|
|
procedure OnDesignerPersistentDeleted(Sender: TObject;
|
|
APersistent: TPersistent);
|
|
procedure OnDesignerModified(Sender: TObject);
|
|
procedure OnDesignerActivated(Sender: TObject);
|
|
procedure OnDesignerCloseQuery(Sender: TObject);
|
|
procedure OnDesignerRenameComponent(ADesigner: TDesigner;
|
|
AComponent: TComponent; const NewName: string);
|
|
procedure OnDesignerViewLFM(Sender: TObject);
|
|
procedure OnDesignerSaveAsXML(Sender: TObject);
|
|
procedure OnDesignerShowObjectInspector(Sender: TObject);
|
|
procedure OnDesignerShowAnchorEditor(Sender: TObject);
|
|
procedure OnDesignerShowTabOrderEditor(Sender: TObject);
|
|
|
|
// control selection
|
|
procedure OnControlSelectionChanged(Sender: TObject; ForceUpdate: Boolean);
|
|
procedure OnControlSelectionPropsChanged(Sender: TObject);
|
|
procedure OnControlSelectionFormChanged(Sender: TObject; OldForm,
|
|
NewForm: TCustomForm);
|
|
|
|
// project inspector
|
|
procedure ProjInspectorOpen(Sender: TObject);
|
|
function ProjInspectorAddUnitToProject(Sender: TObject;
|
|
AnUnitInfo: TUnitInfo): TModalresult;
|
|
function ProjInspectorRemoveFile(Sender: TObject;
|
|
AnUnitInfo: TUnitInfo): TModalresult;
|
|
|
|
// Checks if the UnitDirectory is part of the Unit Search Paths,
|
|
// if not, then ask the user if he wants to extend dependencies
|
|
// or the Unit Search Paths.
|
|
procedure CheckDirIsInUnitSearchPath(UnitInfo: TUnitInfo;
|
|
AllowAddingDependencies: boolean; out DependencyAdded: boolean);
|
|
procedure CheckDirIsInIncludeSearchPath(UnitInfo: TUnitInfo;
|
|
AllowAddingDependencies: boolean; out DependencyAdded: boolean);
|
|
|
|
// compiler options dialog events
|
|
procedure OnCompilerOptionsDialogTest(Sender: TObject);
|
|
function OnCheckCompOptsAndMainSrcForNewUnit(CompOpts: TLazCompilerOptions
|
|
): TModalResult;
|
|
|
|
// unit dependencies events
|
|
procedure UnitDependenciesViewAccessingSources(Sender: TObject);
|
|
function UnitDependenciesViewGetProjectMainFilename(
|
|
Sender: TObject): string;
|
|
procedure UnitDependenciesViewOpenFile(Sender: TObject;
|
|
const Filename: string);
|
|
|
|
// code explorer events
|
|
procedure OnCodeExplorerGetDirectivesTree(Sender: TObject;
|
|
var ADirectivesTool: TDirectivesTool);
|
|
procedure OnCodeExplorerJumpToCode(Sender: TObject; const Filename: string;
|
|
const Caret: TPoint; TopLine: integer);
|
|
procedure OnCodeExplorerShowOptions(Sender: TObject);
|
|
|
|
// CodeToolBoss events
|
|
procedure OnCodeToolNeedsExternalChanges(Manager: TCodeToolManager;
|
|
var Abort: boolean);
|
|
procedure OnBeforeCodeToolBossApplyChanges(Manager: TCodeToolManager;
|
|
var Abort: boolean);
|
|
procedure OnAfterCodeToolBossApplyChanges(Manager: TCodeToolManager);
|
|
function OnCodeToolBossSearchUsedUnit(const SrcFilename: string;
|
|
const TheUnitName, TheUnitInFilename: string): TCodeBuffer;
|
|
function OnCodeToolBossCheckAbort: boolean;
|
|
procedure CodeToolBossGetVirtualDirectoryAlias(Sender: TObject;
|
|
var RealDir: string);
|
|
procedure CodeToolBossGetVirtualDirectoryDefines(DefTree: TDefineTree;
|
|
DirDef: TDirectoryDefines);
|
|
procedure OnCodeToolBossFindDefineProperty(Sender: TObject;
|
|
const PersistentClassName, AncestorClassName, Identifier: string;
|
|
var IsDefined: boolean);
|
|
procedure OnCodeBufferDecodeLoaded(Code: TCodeBuffer;
|
|
const Filename: string; var Source, DiskEncoding, MemEncoding: string);
|
|
procedure OnCodeBufferEncodeSaving(Code: TCodeBuffer;
|
|
const Filename: string; var Source: string);
|
|
function OnCodeToolBossGetMethodName(const Method: TMethod;
|
|
PropOwner: TObject): String;
|
|
procedure CodeToolBossPrepareTree(Sender: TObject);
|
|
procedure CodeToolBossProgress(Sender: TObject; Index, MaxIndex: integer;
|
|
const Msg: string; var Abort: boolean);
|
|
procedure OnCodeToolBossGetIndenterExamples(Sender: TObject;
|
|
Code: TCodeBuffer; Step: integer; // starting at 0
|
|
var CodeBuffers: TFPList; // stopping when CodeBuffers=nil
|
|
var ExpandedFilenames: TStrings
|
|
);
|
|
function CTMacroFunctionProject(Data: Pointer): boolean;
|
|
procedure OnCompilerParseStampIncreased;
|
|
|
|
// MessagesView events
|
|
procedure MessagesViewSelectionChanged(sender: TObject);
|
|
|
|
// SearchResultsView events
|
|
procedure SearchResultsViewSelectionChanged(sender: TObject);
|
|
|
|
// JumpHistoryView events
|
|
procedure JumpHistoryViewSelectionChanged(sender: TObject);
|
|
|
|
// External Tools events
|
|
procedure OnExtToolNeedsOutputFilter(var OutputFilter: TOutputFilter;
|
|
var Abort: boolean);
|
|
procedure OnExtToolFreeOutputFilter(OutputFilter: TOutputFilter;
|
|
ErrorOccurred: boolean);
|
|
|
|
procedure OnGetLayout(Sender: TObject; aFormName: string;
|
|
out aBounds: TRect; out DockSibling: string; out DockAlign: TAlign);
|
|
private
|
|
FUserInputSinceLastIdle: boolean;
|
|
FDisplayState: TDisplayState;
|
|
FLastFormActivated: TCustomForm;// used to find the last form so you can
|
|
// display the correct tab
|
|
FApplicationIsActivate: boolean;
|
|
FCheckingFilesOnDisk: boolean;
|
|
FCheckFilesOnDiskNeeded: boolean;
|
|
FRemoteControlTimer: TTimer;
|
|
FRemoteControlFileAge: integer;
|
|
|
|
FIDECodeToolsDefines: TIDECodetoolsDefines;
|
|
|
|
FRenamingComponents: TFPList; // list of TComponents currently renaming
|
|
FOIHelpProvider: TAbstractIDEHTMLProvider;
|
|
FWaitForClose: Boolean;
|
|
FFixingGlobalComponentLock: integer;
|
|
OldCompilerFilename, OldLanguage: String;
|
|
OIChangedTimer: TIdleTimer;
|
|
|
|
procedure RenameInheritedMethods(AnUnitInfo: TUnitInfo; List: TStrings);
|
|
function OIHelpProvider: TAbstractIDEHTMLProvider;
|
|
function CheckEditorNeedsSave(AEditor: TSourceEditorInterface; IgnoreSharedEdits: Boolean): Boolean;
|
|
protected
|
|
procedure SetToolStatus(const AValue: TIDEToolStatus); override;
|
|
procedure Notification(AComponent: TComponent;
|
|
Operation: TOperation); override;
|
|
|
|
procedure AddRecentProjectFileToEnvironment(const AFilename: string);
|
|
|
|
// methods for start
|
|
procedure StartProtocol;
|
|
procedure LoadGlobalOptions;
|
|
procedure SetupMainMenu; override;
|
|
procedure SetupStandardIDEMenuItems;
|
|
procedure SetupStandardProjectTypes;
|
|
procedure SetRecentFilesMenu;
|
|
procedure SetRecentProjectFilesMenu;
|
|
procedure SetupFileMenu; override;
|
|
procedure SetupEditMenu; override;
|
|
procedure SetupSearchMenu; override;
|
|
procedure SetupViewMenu; override;
|
|
procedure SetupSourceMenu; override;
|
|
procedure SetupProjectMenu; override;
|
|
procedure SetupRunMenu; override;
|
|
procedure SetupPackageMenu; override;
|
|
procedure SetupToolsMenu; override;
|
|
procedure SetupWindowsMenu; override;
|
|
procedure SetupHelpMenu; override;
|
|
procedure LoadMenuShortCuts; override;
|
|
procedure ConnectMainBarEvents;
|
|
procedure SetupSpeedButtons;
|
|
procedure SetupDialogs;
|
|
procedure SetupComponentPalette;
|
|
procedure SetupHints;
|
|
procedure SetupOutputFilter;
|
|
procedure SetupObjectInspector;
|
|
procedure SetupFormEditor;
|
|
procedure SetupSourceNotebook;
|
|
procedure SetupTransferMacros;
|
|
procedure SetupCodeMacros;
|
|
procedure SetupControlSelection;
|
|
procedure SetupIDECommands;
|
|
procedure SetupIDEMsgQuickFixItems;
|
|
procedure SetupStartProject;
|
|
procedure SetupRemoteControl;
|
|
procedure SetupIDEWindowsLayout;
|
|
procedure RestoreIDEWindows;
|
|
procedure FreeIDEWindows;
|
|
function CloseQueryIDEWindows: boolean;
|
|
|
|
procedure ReloadMenuShortCuts;
|
|
|
|
// methods for 'new unit'
|
|
function CreateNewCodeBuffer(Descriptor: TProjectFileDescriptor;
|
|
NewOwner: TObject; NewFilename: string; var NewCodeBuffer: TCodeBuffer;
|
|
var NewUnitName: string): TModalResult;
|
|
function CreateNewForm(NewUnitInfo: TUnitInfo;
|
|
AncestorType: TPersistentClass; ResourceCode: TCodeBuffer;
|
|
UseCreateFormStatements, DisableAutoSize: Boolean): TModalResult;
|
|
|
|
// methods for 'save unit'
|
|
function DoShowSaveFileAsDialog(var AFilename: string; AnUnitInfo: TUnitInfo;
|
|
var ResourceCode: TCodeBuffer; CanAbort: boolean): TModalResult;
|
|
function DoSaveUnitComponent(AnUnitInfo: TUnitInfo;
|
|
ResourceCode, LFMCode: TCodeBuffer; Flags: TSaveFlags): TModalResult;
|
|
function DoRemoveDanglingEvents(AnUnitInfo: TUnitInfo;
|
|
OkOnCodeErrors: boolean): TModalResult;
|
|
function DoRenameUnit(AnUnitInfo: TUnitInfo; NewFilename, NewUnitName: string;
|
|
var ResourceCode: TCodeBuffer): TModalresult;
|
|
|
|
// methods for 'open unit' and 'open main unit'
|
|
function DoOpenNotExistingFile(const AFileName:string;
|
|
Flags: TOpenFlags): TModalResult;
|
|
function DoOpenUnknownFile(const AFileName:string; Flags: TOpenFlags;
|
|
var NewUnitInfo: TUnitInfo; var Handled: boolean): TModalResult;
|
|
function DoOpenFileInSourceEditor(AnEditorInfo: TUnitEditorInfo;
|
|
PageIndex, WindowIndex: integer; Flags: TOpenFlags): TModalResult;
|
|
function DoLoadResourceFile(AnUnitInfo: TUnitInfo;
|
|
var LFMCode, ResourceCode: TCodeBuffer;
|
|
IgnoreSourceErrors, AutoCreateResourceCode, ShowAbort: boolean): TModalResult;
|
|
function DoLoadLFM(AnUnitInfo: TUnitInfo; OpenFlags: TOpenFlags;
|
|
CloseFlags: TCloseFlags): TModalResult;
|
|
function DoLoadLFM(AnUnitInfo: TUnitInfo; LFMBuf: TCodeBuffer;
|
|
OpenFlags: TOpenFlags;
|
|
CloseFlags: TCloseFlags): TModalResult;
|
|
function FindBaseComponentClass(const AComponentClassName,
|
|
DescendantClassName: string;
|
|
out AComponentClass: TComponentClass): boolean;
|
|
function DoLoadAncestorDependencyHidden(AnUnitInfo: TUnitInfo;
|
|
const DescendantClassName: string;
|
|
OpenFlags: TOpenFlags;
|
|
out AncestorClass: TComponentClass;
|
|
out AncestorUnitInfo: TUnitInfo): TModalResult;
|
|
function DoLoadComponentDependencyHidden(AnUnitInfo: TUnitInfo;
|
|
const AComponentClassName: string; Flags: TOpenFlags;
|
|
MustHaveLFM: boolean;
|
|
var AComponentClass: TComponentClass;
|
|
var ComponentUnitInfo: TUnitInfo): TModalResult;
|
|
|
|
// methods for 'close unit'
|
|
function CloseUnitComponent(AnUnitInfo: TUnitInfo; Flags: TCloseFlags
|
|
): TModalResult;
|
|
function CloseDependingUnitComponents(AnUnitInfo: TUnitInfo;
|
|
Flags: TCloseFlags): TModalResult;
|
|
function UnitComponentIsUsed(AnUnitInfo: TUnitInfo;
|
|
CheckHasDesigner: boolean): boolean;
|
|
function RemoveFilesFromProject(AProject: TProject; UnitInfos: TFPList): TModalResult;
|
|
|
|
// methods for creating a project
|
|
function CreateProjectObject(ProjectDesc,
|
|
FallbackProjectDesc: TProjectDescriptor): TProject; override;
|
|
procedure OnLoadProjectInfoFromXMLConfig(TheProject: TProject;
|
|
XMLConfig: TXMLConfig;
|
|
Merge: boolean);
|
|
procedure OnSaveProjectInfoToXMLConfig(TheProject: TProject;
|
|
XMLConfig: TXMLConfig; WriteFlags: TProjectWriteFlags);
|
|
procedure OnProjectGetTestDirectory(TheProject: TProject;
|
|
out TestDir: string);
|
|
procedure OnProjectChangeInfoFile(TheProject: TProject);
|
|
procedure OnSaveProjectUnitSessionInfo(AUnitInfo: TUnitInfo);
|
|
|
|
// methods for 'save project'
|
|
function SaveProjectInfo(var Flags: TSaveFlags): TModalResult;
|
|
procedure GetMainUnit(var MainUnitInfo: TUnitInfo;
|
|
var MainUnitSrcEdit: TSourceEditor; UpdateModified: boolean);
|
|
procedure SaveSrcEditorProjectSpecificSettings(AnEditorInfo: TUnitEditorInfo);
|
|
procedure SaveSourceEditorProjectSpecificSettings;
|
|
function DoShowSaveProjectAsDialog(UseMainSourceFile: boolean): TModalResult;
|
|
|
|
// methods for open project, create project from source
|
|
function DoCompleteLoadingProjectInfo: TModalResult;
|
|
|
|
// methods for publish project
|
|
procedure OnCopyFile(const Filename: string; var Copy: boolean; Data: TObject);
|
|
procedure OnCopyError(const ErrorData: TCopyErrorData;
|
|
var Handled: boolean; Data: TObject);
|
|
public
|
|
class procedure ParseCmdLineOptions;
|
|
|
|
constructor Create(TheOwner: TComponent); override;
|
|
procedure StartIDE; override;
|
|
destructor Destroy; override;
|
|
procedure CreateOftenUsedForms; override;
|
|
procedure UpdateDefaultPascalFileExtensions;
|
|
function DoResetToolStatus(AFlags: TResetToolFlags): boolean; override;
|
|
|
|
// files/units
|
|
function DoNewFile(NewFileDescriptor: TProjectFileDescriptor;
|
|
var NewFilename: string; const NewSource: string;
|
|
NewFlags: TNewFlags; NewOwner: TObject): TModalResult; override;
|
|
function DoNewOther: TModalResult;
|
|
procedure CreateFileDialogFilterForSourceEditorFiles(Filter: string;
|
|
out AllEditorExt, AllFilter: string);
|
|
|
|
function DoSaveEditorFile(PageIndex:integer;
|
|
Flags: TSaveFlags): TModalResult; override;
|
|
deprecated {$IFDEF VER2_5}'use method with EditorObject'{$ENDIF}; // deprecated in 0.9.29 March 2010
|
|
function DoSaveEditorFile(AEditor: TSourceEditorInterface;
|
|
Flags: TSaveFlags): TModalResult; override;
|
|
|
|
function DoCloseEditorFile(PageIndex:integer;
|
|
Flags: TCloseFlags):TModalResult; override;
|
|
deprecated {$IFDEF VER2_5}'use method with EditorObject'{$ENDIF}; // deprecated in 0.9.29 March 2010
|
|
function DoCloseEditorFile(AEditor: TSourceEditorInterface;
|
|
Flags: TCloseFlags):TModalResult; override;
|
|
function DoCloseEditorFile(const Filename: string;
|
|
Flags: TCloseFlags): TModalResult; override;
|
|
|
|
|
|
function DoOpenEditorFile(AFileName: string; PageIndex: integer;
|
|
Flags: TOpenFlags): TModalResult; override;
|
|
deprecated {$IFDEF VER2_5}'use method with WindowIndex'{$ENDIF}; // deprecated in 0.9.29 March 2010
|
|
function DoOpenEditorFile(AFileName:string; PageIndex, WindowIndex: integer;
|
|
Flags: TOpenFlags): TModalResult; override;
|
|
function DoOpenEditorFile(AFileName:string; PageIndex, WindowIndex: integer;
|
|
AEditorInfo: TUnitEditorInfo;
|
|
Flags: TOpenFlags): TModalResult;
|
|
|
|
function DoOpenFileAtCursor(Sender: TObject): TModalResult;
|
|
function DoOpenFileAndJumpToIdentifier(const AFilename, AnIdentifier: string;
|
|
PageIndex: integer; Flags: TOpenFlags): TModalResult; override;
|
|
deprecated {$IFDEF VER2_5}'use method with WindowIndex'{$ENDIF}; // deprecated in 0.9.29 March 2010
|
|
function DoOpenFileAndJumpToIdentifier(const AFilename, AnIdentifier: string;
|
|
PageIndex, WindowIndex: integer; Flags: TOpenFlags): TModalResult; override;
|
|
function DoOpenFileAndJumpToPos(const AFilename: string;
|
|
const CursorPosition: TPoint; TopLine: integer;
|
|
PageIndex: integer; Flags: TOpenFlags): TModalResult; override;
|
|
deprecated {$IFDEF VER2_5}'use method with WindowIndex'{$ENDIF}; // deprecated in 0.9.29 March 2010
|
|
function DoOpenFileAndJumpToPos(const AFilename: string;
|
|
const CursorPosition: TPoint; TopLine: integer;
|
|
PageIndex, WindowIndex: integer; Flags: TOpenFlags): TModalResult; override;
|
|
function DoRevertEditorFile(const Filename: string): TModalResult; override;
|
|
function DoOpenComponent(const UnitFilename: string; OpenFlags: TOpenFlags;
|
|
CloseFlags: TCloseFlags;
|
|
out Component: TComponent): TModalResult; override;
|
|
function DoFixupComponentReferences(
|
|
RootComponent: TComponent;
|
|
OpenFlags: TOpenFlags): TModalResult; override;
|
|
procedure BeginFixupComponentReferences;
|
|
procedure EndFixupComponentReferences;
|
|
function DoSaveAll(Flags: TSaveFlags): TModalResult;
|
|
procedure DoRestart;
|
|
procedure DoExecuteRemoteControl;
|
|
function DoOpenMainUnit(PageIndex, WindowIndex: integer; Flags: TOpenFlags): TModalResult;
|
|
function DoRevertMainUnit: TModalResult;
|
|
function DoViewUnitsAndForms(OnlyForms: boolean): TModalResult;
|
|
function DoSelectFrame: TComponentClass;
|
|
procedure DoViewUnitDependencies(Show: boolean);
|
|
procedure DoViewJumpHistory(Show: boolean);
|
|
procedure DoViewUnitInfo;
|
|
procedure DoShowCodeExplorer(Show: boolean);
|
|
procedure DoShowCodeBrowser(Show: boolean);
|
|
procedure DoShowRestrictionBrowser(Show: boolean; const RestrictedName: String = '');
|
|
procedure DoShowComponentList(Show: boolean);
|
|
procedure CreateIDEWindow(Sender: TObject; aFormName: string;
|
|
var AForm: TCustomForm; DoDisableAutoSizing: boolean);
|
|
function CreateNewUniqueFilename(const Prefix, Ext: string;
|
|
NewOwner: TObject; Flags: TSearchIDEFileFlags; TryWithoutNumber: boolean
|
|
): string; override;
|
|
procedure MarkUnitsModifiedUsingSubComponent(SubComponent: TComponent);
|
|
|
|
function GetAvailableUnitEditorInfo(AnUnitInfo: TUnitInfo;
|
|
ACaretPoint: TPoint; WantedTopLine: integer = -1): TUnitEditorInfo;
|
|
|
|
// project(s)
|
|
procedure DoLoadDefaultCompilerOptions(AProject: TProject);
|
|
function DoNewProject(ProjectDesc: TProjectDescriptor): TModalResult; override;
|
|
function DoSaveProject(Flags: TSaveFlags): TModalResult; override;
|
|
function DoCloseProject: TModalResult; override;
|
|
function DoOpenProjectFile(AFileName: string;
|
|
Flags: TOpenFlags): TModalResult; override;
|
|
function DoPublishProject(Flags: TSaveFlags;
|
|
ShowDialog: boolean): TModalResult; override;
|
|
function DoImExportCompilerOptions(Sender: TObject; out ImportExportResult: TImportExportOptionsResult): TModalResult; override;
|
|
procedure DoShowProjectInspector(Show: boolean); override;
|
|
function DoAddActiveUnitToProject: TModalResult;
|
|
function DoRemoveFromProjectDialog: TModalResult;
|
|
function DoWarnAmbiguousFiles: TModalResult;
|
|
procedure DoUpdateProjectResourceInfo;
|
|
function DoSaveForBuild(AReason: TCompileReason): TModalResult; override;
|
|
function DoCheckIfProjectNeedsCompilation(AProject: TProject;
|
|
const CompilerFilename, CompilerParams, SrcFilename: string;
|
|
out NeedBuildAllFlag: boolean): TModalResult;
|
|
function DoBuildProject(const AReason: TCompileReason;
|
|
Flags: TProjectBuildFlags): TModalResult; override;
|
|
function UpdateProjectPOFile(AProject: TProject): TModalResult;
|
|
function DoAbortBuild: TModalResult;
|
|
procedure DoQuickCompile;
|
|
function DoInitProjectRun: TModalResult; override;
|
|
function DoRunProject: TModalResult;
|
|
function SomethingOfProjectIsModified(Verbose: boolean = false): boolean;
|
|
function DoCreateProjectForProgram(ProgramBuf: TCodeBuffer): TModalResult;
|
|
function DoSaveProjectIfChanged: TModalResult;
|
|
function DoSaveProjectToTestDirectory(Flags: TSaveFlags): TModalResult;
|
|
function DoTestCompilerSettings(
|
|
TheCompilerOptions: TCompilerOptions): TModalResult;
|
|
function CheckMainSrcLCLInterfaces(Silent: boolean): TModalResult;
|
|
function QuitIDE: boolean;
|
|
|
|
// edit menu
|
|
procedure DoCommand(ACommand: integer); override;
|
|
procedure DoSourceEditorCommand(EditorCommand: integer);
|
|
procedure UpdateCustomToolsInMenu;
|
|
|
|
// external tools
|
|
function PrepareForCompile: TModalResult; override;
|
|
function OnRunExternalTool(Tool: TIDEExternalToolOptions): TModalResult;
|
|
function DoRunExternalTool(Index: integer; ShowAbort: Boolean): TModalResult;
|
|
function DoSaveBuildIDEConfigs(Flags: TBuildLazarusFlags): TModalResult; override;
|
|
function DoManageExamples(): TModalResult; override;
|
|
function DoBuildLazarus(Flags: TBuildLazarusFlags): TModalResult; override;
|
|
function DoBuildAdvancedLazarus(ProfileNames: TStringList): TModalResult;
|
|
function DoBuildFile(ShowAbort: Boolean): TModalResult;
|
|
function DoRunFile: TModalResult;
|
|
function DoConfigBuildFile: TModalResult;
|
|
function GetIDEDirectives(AnUnitInfo: TUnitInfo;
|
|
DirectiveList: TStrings): TModalResult;
|
|
|
|
// useful information methods
|
|
procedure GetCurrentUnit(out ActiveSourceEditor: TSourceEditor;
|
|
out ActiveUnitInfo: TUnitInfo); override;
|
|
procedure GetUnitWithPageIndex(PageIndex, WindowIndex: integer;
|
|
var ActiveSourceEditor: TSourceEditor; var ActiveUnitInfo: TUnitInfo); override;
|
|
deprecated; // deprecated in 0.9.29 March 2010
|
|
procedure GetDesignerUnit(ADesigner: TDesigner;
|
|
var ActiveSourceEditor: TSourceEditor; var ActiveUnitInfo: TUnitInfo); override;
|
|
function GetProjectFileForProjectEditor(AEditor: TSourceEditorInterface): TLazProjectFile; override;
|
|
function GetDesignerForProjectEditor(AEditor: TSourceEditorInterface;
|
|
LoadForm: boolean): TIDesigner; override;
|
|
function GetDesignerWithProjectFile(AFile: TLazProjectFile;
|
|
LoadForm: boolean): TIDesigner; override;
|
|
function GetDesignerFormOfSource(AnUnitInfo: TUnitInfo;
|
|
LoadForm: boolean): TCustomForm;
|
|
function GetProjectFileWithRootComponent(AComponent: TComponent): TLazProjectFile; override;
|
|
function GetProjectFileWithDesigner(ADesigner: TIDesigner): TLazProjectFile; override;
|
|
procedure GetObjectInspectorUnit(
|
|
var ActiveSourceEditor: TSourceEditor; var ActiveUnitInfo: TUnitInfo); override;
|
|
procedure GetUnitWithForm(AForm: TCustomForm;
|
|
var ActiveSourceEditor: TSourceEditor; var ActiveUnitInfo: TUnitInfo); override;
|
|
procedure GetUnitWithPersistent(APersistent: TPersistent;
|
|
var ActiveSourceEditor: TSourceEditor; var ActiveUnitInfo: TUnitInfo); override;
|
|
function CreateSrcEditPageName(const AnUnitName, AFilename: string;
|
|
IgnoreEditor: TSourceEditor): string;
|
|
function GetAncestorUnit(AnUnitInfo: TUnitInfo): TUnitInfo;
|
|
function GetAncestorLookupRoot(AnUnitInfo: TUnitInfo): TComponent;
|
|
procedure UpdateSaveMenuItemsAndButtons(UpdateSaveAll: boolean);
|
|
|
|
// useful file methods
|
|
function FindUnitFile(const AFilename: string; TheOwner: TObject = nil;
|
|
Flags: TFindUnitFileFlags = []): string; override;
|
|
function FindSourceFile(const AFilename, BaseDirectory: string;
|
|
Flags: TFindSourceFlags): string; override;
|
|
function FileExistsInIDE(const Filename: string;
|
|
SearchFlags: TProjectFileSearchFlags): boolean;
|
|
function LoadIDECodeBuffer(var ACodeBuffer: TCodeBuffer;
|
|
const AFilename: string;
|
|
Flags: TLoadBufferFlags; ShowAbort: boolean): TModalResult;
|
|
function DoLoadMemoryStreamFromFile(MemStream: TMemoryStream;
|
|
const AFilename:string): TModalResult;
|
|
function DoRenameUnitLowerCase(AnUnitInfo: TUnitInfo;
|
|
AskUser: boolean): TModalresult;
|
|
function DoCheckFilesOnDisk(Instantaneous: boolean = false): TModalResult; override;
|
|
function DoPublishModule(Options: TPublishModuleOptions;
|
|
const SrcDirectory, DestDirectory: string
|
|
): TModalResult; override;
|
|
procedure AbortBuild; override;
|
|
|
|
// useful frontend methods
|
|
procedure DoSwitchToFormSrc(var ActiveSourceEditor:TSourceEditor;
|
|
var ActiveUnitInfo:TUnitInfo);
|
|
procedure DoSwitchToFormSrc(ADesigner: TDesigner;
|
|
var ActiveSourceEditor:TSourceEditor; var ActiveUnitInfo:TUnitInfo);
|
|
procedure UpdateCaption; override;
|
|
procedure HideIDE; override;
|
|
procedure HideUnmodifiedDesigners;
|
|
procedure UnhideIDE; override;
|
|
|
|
// methods for codetools
|
|
function InitCodeToolBoss: boolean;
|
|
procedure ActivateCodeToolAbortableMode;
|
|
function BeginCodeTools: boolean; override;
|
|
function BeginCodeTool(var ActiveSrcEdit: TSourceEditor;
|
|
out ActiveUnitInfo: TUnitInfo;
|
|
Flags: TCodeToolsFlags): boolean;
|
|
function BeginCodeTool(ADesigner: TDesigner;
|
|
var ActiveSrcEdit: TSourceEditor;
|
|
out ActiveUnitInfo: TUnitInfo;
|
|
Flags: TCodeToolsFlags): boolean;
|
|
function DoJumpToSourcePosition(const Filename: string;
|
|
NewX, NewY, NewTopLine: integer;
|
|
Flags: TJumpToCodePosFlags = [jfFocusEditor]): TModalResult; override;
|
|
function DoJumpToCodePosition(
|
|
ActiveSrcEdit: TSourceEditorInterface;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
NewSource: TCodeBuffer; NewX, NewY, NewTopLine: integer;
|
|
Flags: TJumpToCodePosFlags = [jfFocusEditor]): TModalResult; override;
|
|
procedure DoJumpToCodeToolBossError; override;
|
|
procedure UpdateSourceNames;
|
|
function NeedSaveSourceEditorChangesToCodeCache(PageIndex: integer): boolean; override;
|
|
deprecated {$IFDEF VER2_5}'use method with EditorObject'{$ENDIF}; // deprecated in 0.9.29 March 2010
|
|
function NeedSaveSourceEditorChangesToCodeCache(AEditor: TSourceEditorInterface): boolean; override;
|
|
function SaveSourceEditorChangesToCodeCache(PageIndex: integer): boolean; override;
|
|
deprecated {$IFDEF VER2_5}'use method with EditorObject'{$ENDIF}; // deprecated in 0.9.29 March 2010
|
|
function SaveSourceEditorChangesToCodeCache(AEditor: TSourceEditorInterface): boolean; override;
|
|
procedure ApplyCodeToolChanges;
|
|
procedure DoJumpToOtherProcedureSection;
|
|
procedure DoFindDeclarationAtCursor;
|
|
procedure DoFindDeclarationAtCaret(const LogCaretXY: TPoint);
|
|
function DoFindRenameIdentifier(Rename: boolean): TModalResult;
|
|
function DoReplaceUnitUse(OldFilename, OldUnitName,
|
|
NewFilename, NewUnitName: string;
|
|
IgnoreErrors, Quiet, Confirm: boolean): TModalResult;
|
|
function DoShowAbstractMethods: TModalResult;
|
|
function DoRemoveEmptyMethods: TModalResult;
|
|
function DoRemoveUnusedUnits: TModalResult;
|
|
function DoUseUnit: TModalResult;
|
|
function DoFindOverloads: TModalResult;
|
|
function DoInitIdentCompletion(JumpToError: boolean): boolean;
|
|
function DoShowCodeContext(JumpToError: boolean): boolean;
|
|
procedure DoCompleteCodeAtCursor;
|
|
procedure DoExtractProcFromSelection;
|
|
function DoCheckSyntax: TModalResult;
|
|
procedure DoGoToPascalBlockOtherEnd;
|
|
procedure DoGoToPascalBlockStart;
|
|
procedure DoJumpToGuessedUnclosedBlock(FindNextUTF8: boolean);
|
|
procedure DoJumpToGuessedMisplacedIFDEF(FindNextUTF8: boolean);
|
|
|
|
procedure DoGotoIncludeDirective;
|
|
procedure SaveIncludeLinks;
|
|
function SelectProjectItems(ItemList: TStringList;
|
|
ItemType: TIDEProjectItem;
|
|
MultiSelect: boolean;
|
|
var MultiSelectCheckedState: Boolean): TModalResult;
|
|
|
|
// tools
|
|
function DoMakeResourceString: TModalResult;
|
|
function DoDiff: TModalResult;
|
|
function DoFindInFiles: TModalResult;
|
|
procedure DoInsertGUID;
|
|
procedure DoInsertFilename;
|
|
|
|
// conversion
|
|
function DoConvertDFMtoLFM: TModalResult;
|
|
function DoCheckLFMInEditor(Quiet: boolean): TModalResult;
|
|
function DoConvertDelphiUnit(const DelphiFilename: string; CanAbort: boolean): TModalResult;
|
|
function DoConvertDelphiProject(const DelphiFilename: string): TModalResult;
|
|
function DoConvertDelphiPackage(const DelphiFilename: string): TModalResult;
|
|
|
|
// message view
|
|
function DoJumpToCompilerMessage(Index:integer;
|
|
FocusEditor: boolean): boolean; override;
|
|
procedure DoJumpToNextError(DirectionDown: boolean); override;
|
|
procedure DoShowMessagesView(BringToFront: boolean = true); override;
|
|
procedure DoArrangeSourceEditorAndMessageView(PutOnTop: boolean);
|
|
|
|
// methods for debugging, compiling and external tools
|
|
function GetTestBuildDirectory: string; override;
|
|
procedure OnMacroSubstitution(TheMacro: TTransferMacro;
|
|
const MacroName: string; var s: string;
|
|
const Data: PtrInt; var Handled, Abort: boolean;
|
|
Depth: integer);
|
|
procedure GetIDEFileState(Sender: TObject; const AFilename: string;
|
|
NeededFlags: TIDEFileStateFlags; out ResultFlags: TIDEFileStateFlags); override;
|
|
|
|
// search results
|
|
function DoJumpToSearchResult(FocusEditor: boolean): boolean;
|
|
procedure DoShowSearchResultsView(Show, BringToFront: boolean);
|
|
|
|
// form editor and designer
|
|
procedure DoBringToFrontFormOrUnit;
|
|
procedure DoBringToFrontFormOrInspector(ForceInspector: boolean);
|
|
procedure DoShowDesignerFormOfCurrentSrc;
|
|
procedure DoShowSourceOfActiveDesignerForm;
|
|
procedure SetDesigning(AComponent: TComponent; Value: Boolean);
|
|
procedure SetDesignInstance(AComponent: TComponent; Value: Boolean);
|
|
function CreateDesignerForComponent(AnUnitInfo: TUnitInfo;
|
|
AComponent: TComponent): TCustomForm;
|
|
procedure InvalidateAllDesignerForms;
|
|
procedure UpdateIDEComponentPalette;
|
|
procedure ShowDesignerForm(AForm: TCustomForm);
|
|
procedure DoViewAnchorEditor(Show: boolean);
|
|
procedure DoViewTabOrderEditor(Show: boolean);
|
|
procedure DoToggleViewComponentPalette;
|
|
procedure DoToggleViewIDESpeedButtons;
|
|
|
|
// editor and environment options
|
|
procedure SaveEnvironment; override;
|
|
procedure LoadDesktopSettings(TheEnvironmentOptions: TEnvironmentOptions);
|
|
procedure SaveDesktopSettings(TheEnvironmentOptions: TEnvironmentOptions);
|
|
end;
|
|
|
|
|
|
const
|
|
CodeToolsIncludeLinkFile = 'includelinks.xml';
|
|
|
|
var
|
|
ShowSplashScreen: boolean = false;
|
|
|
|
implementation
|
|
|
|
var
|
|
SkipAutoLoadingLastProject: boolean = false;
|
|
StartedByStartLazarus: boolean = false;
|
|
ShowSetupDialog: boolean = false;
|
|
|
|
function FindDesignComponent(const aName: string): TComponent;
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
Result:=nil;
|
|
AnUnitInfo:=Project1.FirstUnitWithComponent;
|
|
while AnUnitInfo<>nil do begin
|
|
if SysUtils.CompareText(aName,AnUnitInfo.Component.Name)=0 then begin
|
|
Result:=AnUnitInfo.Component;
|
|
exit;
|
|
end;
|
|
AnUnitInfo:=AnUnitInfo.NextUnitWithComponent;
|
|
end;
|
|
end;
|
|
|
|
//==============================================================================
|
|
|
|
|
|
{ TMainIDE }
|
|
|
|
{-------------------------------------------------------------------------------
|
|
procedure TMainIDE.ParseCmdLineOptions;
|
|
|
|
Parses the command line for the IDE.
|
|
-------------------------------------------------------------------------------}
|
|
class procedure TMainIDE.ParseCmdLineOptions;
|
|
const
|
|
space = ' ';
|
|
var
|
|
AHelp: TStringList;
|
|
HelpLang: string;
|
|
|
|
procedure AddHelp(Args: array of const);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := Low(Args) to High(Args) do
|
|
begin
|
|
case Args[i].VType of
|
|
vtInteger: AHelp.Add(dbgs(Args[i].vinteger));
|
|
vtInt64: AHelp.Add(dbgs(Args[i].VInt64^));
|
|
vtQWord: AHelp.Add(dbgs(Args[i].VQWord^));
|
|
vtBoolean: AHelp.Add(dbgs(Args[i].vboolean));
|
|
vtExtended: AHelp.Add(dbgs(Args[i].VExtended^));
|
|
{$ifdef FPC_CURRENCY_IS_INT64}
|
|
// fpc 2.x has troubles in choosing the right dbgs()
|
|
// so we convert here
|
|
vtCurrency: AHelp.Add(dbgs(int64(Args[i].vCurrency^)/10000, 4));
|
|
{$else}
|
|
vtCurrency: AHelp.Add(dbgs(Args[i].vCurrency^));
|
|
{$endif}
|
|
vtString: AHelp.Add(Args[i].VString^);
|
|
vtAnsiString: AHelp.Add(AnsiString(Args[i].VAnsiString));
|
|
vtChar: AHelp.Add(Args[i].VChar);
|
|
vtPChar: AHelp.Add(Args[i].VPChar);
|
|
vtPWideChar: AHelp.Add(Args[i].VPWideChar);
|
|
vtWideChar: AHelp.Add(Args[i].VWideChar);
|
|
vtWidestring: AHelp.Add(WideString(Args[i].VWideString));
|
|
vtObject: AHelp.Add(DbgSName(Args[i].VObject));
|
|
vtClass: AHelp.Add(DbgSName(Args[i].VClass));
|
|
vtPointer: AHelp.Add(Dbgs(Args[i].VPointer));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure WriteHelp(const AText: string);
|
|
begin
|
|
if TextRec(Output).Mode = fmClosed then
|
|
MessageDlg(AText, mtInformation, [mbOk], 0)
|
|
else
|
|
WriteLn(UTF8ToConsole(AText));
|
|
Application.Terminate;
|
|
end;
|
|
|
|
begin
|
|
StartedByStartLazarus:=false;
|
|
SkipAutoLoadingLastProject:=false;
|
|
EnableRemoteControl:=false;
|
|
if IsHelpRequested then
|
|
begin
|
|
EnvironmentOptions := nil;
|
|
HelpLang := GetLanguageSpecified;
|
|
if HelpLang <> '' then
|
|
TranslateResourceStrings(ProgramDirectory(true), HelpLang)
|
|
else
|
|
begin
|
|
EnvironmentOptions := TEnvironmentOptions.Create;
|
|
EnvironmentOptions.CreateConfig;
|
|
EnvironmentOptions.Load(true);
|
|
TranslateResourceStrings(ProgramDirectory(true), EnvironmentOptions.LanguageID);
|
|
end;
|
|
|
|
AHelp := TStringList.Create;
|
|
AddHelp([lislazarusOptionsProjectFilename]);
|
|
AddHelp(['']);
|
|
AddHelp([lisIDEOptions]);
|
|
AddHelp(['']);
|
|
AddHelp(['--help or -? ', listhisHelpMessage]);
|
|
AddHelp(['']);
|
|
AddHelp(['-v or --version ', lisShowVersionAndExit]);
|
|
AddHelp(['']);
|
|
AddHelp([ShowSetupDialogOptLong]);
|
|
AddHelp([BreakString(space+lisShowSetupDialogForMostImportantSettings, 75, 22)]);
|
|
AddHelp(['']);
|
|
AddHelp([PrimaryConfPathOptLong, ' <path>']);
|
|
AddHelp(['or ', PrimaryConfPathOptShort, ' <path>']);
|
|
AddHelp([BreakString(space+lisprimaryConfigDirectoryWhereLazarusStoresItsConfig,
|
|
75, 22), LazConf.GetPrimaryConfigPath]);
|
|
AddHelp(['']);
|
|
AddHelp([SecondaryConfPathOptLong,' <path>']);
|
|
AddHelp(['or ',SecondaryConfPathOptShort,' <path>']);
|
|
AddHelp([BreakString(space+lissecondaryConfigDirectoryWhereLazarusSearchesFor,
|
|
75, 22), LazConf.GetSecondaryConfigPath]);
|
|
AddHelp(['']);
|
|
AddHelp([DebugLogOpt,' <file>']);
|
|
AddHelp([BreakString(space+lisFileWhereDebugOutputIsWritten, 75, 22)]);
|
|
AddHelp(['']);
|
|
AddHelp([NoSplashScreenOptLong]);
|
|
AddHelp(['or ',NoSplashScreenOptShort]);
|
|
AddHelp([BreakString(space+lisDoNotShowSplashScreen,75, 22)]);
|
|
AddHelp(['']);
|
|
AddHelp([SkipLastProjectOpt]);
|
|
AddHelp([BreakString(space+lisSkipLoadingLastProject, 75, 22)]);
|
|
AddHelp(['']);
|
|
AddHelp([LanguageOpt]);
|
|
AddHelp([BreakString(space+lisOverrideLanguage,75, 22)]);
|
|
AddHelp(['']);
|
|
AddHelp([LazarusDirOpt,'<directory>']);
|
|
AddHelp([BreakString(space+lisLazarusDirOverride, 75, 22)]);
|
|
AddHelp(['']);
|
|
AddHelp([lisCmdLineLCLInterfaceSpecificOptions]);
|
|
AddHelp(['']);
|
|
AddHelp([GetCmdLineParamDescForInterface]);
|
|
AddHelp(['']);
|
|
|
|
WriteHelp(AHelp.Text);
|
|
AHelp.Free;
|
|
FreeThenNil(EnvironmentOptions);
|
|
exit;
|
|
end;
|
|
if IsVersionRequested then
|
|
begin
|
|
WriteHelp(GetLazarusVersionString+' '+lisSVNRevision+LazarusRevisionStr);
|
|
exit;
|
|
end;
|
|
|
|
ParseGuiCmdLineParams(SkipAutoLoadingLastProject, StartedByStartLazarus,
|
|
EnableRemoteControl, ShowSplashScreen, ShowSetupDialog);
|
|
|
|
DebugLn('TMainIDE.ParseCmdLineOptions:');
|
|
Debugln(' PrimaryConfigPath="',UTF8ToConsole(GetPrimaryConfigPath),'"');
|
|
Debugln(' SecondaryConfigPath="',UTF8ToConsole(GetSecondaryConfigPath),'"');
|
|
end;
|
|
|
|
procedure TMainIDE.LoadGlobalOptions;
|
|
// load environment, miscellaneous, editor and codetools options
|
|
begin
|
|
EnvironmentOptions := TEnvironmentOptions.Create;
|
|
with EnvironmentOptions do
|
|
begin
|
|
OnBeforeRead := @DoEnvironmentOptionsBeforeRead;
|
|
OnBeforeWrite := @DoEnvironmentOptionsBeforeWrite;
|
|
OnAfterWrite := @DoEnvironmentOptionsAfterWrite;
|
|
CreateConfig;
|
|
Load(false);
|
|
if Application.HasOption('language') then
|
|
begin
|
|
debugln('TMainIDE.LoadGlobalOptions overriding language with command line: ',
|
|
Application.GetOptionValue('language'));
|
|
EnvironmentOptions.LanguageID := Application.GetOptionValue('language');
|
|
end;
|
|
if Application.HasOption('lazarusdir') then
|
|
begin
|
|
debugln('TMainIDE.LoadGlobalOptions overriding Lazarusdir with command line: ',
|
|
Application.GetOptionValue('lazarusdir'));
|
|
EnvironmentOptions.Lazarusdirectory:= Application.GetOptionValue('lazarusdir');
|
|
end;
|
|
|
|
Application.BidiMode := Application.Direction(EnvironmentOptions.LanguageID);
|
|
|
|
TranslateResourceStrings(EnvironmentOptions.LazarusDirectory,
|
|
EnvironmentOptions.LanguageID);
|
|
|
|
Application.ShowButtonGlyphs := ShowButtonGlyphs;
|
|
Application.ShowMenuGlyphs := ShowMenuGlyphs;
|
|
end;
|
|
ExternalTools.OnNeedsOutputFilter := @OnExtToolNeedsOutputFilter;
|
|
ExternalTools.OnFreeOutputFilter := @OnExtToolFreeOutputFilter;
|
|
UpdateDefaultPascalFileExtensions;
|
|
|
|
EditorOpts := TEditorOptions.Create;
|
|
EditorOpts.OnBeforeRead := @DoEditorOptionsBeforeRead;
|
|
EditorOpts.OnAfterWrite := @DoEditorOptionsAfterWrite;
|
|
SetupIDECommands;
|
|
SetupIDEMsgQuickFixItems;
|
|
EditorOpts.Load;
|
|
|
|
ExternalTools.LoadShortCuts(EditorOpts.KeyMap);
|
|
|
|
MiscellaneousOptions := TMiscellaneousOptions.Create;
|
|
MiscellaneousOptions.Load;
|
|
|
|
CodeToolsOpts := TCodeToolsOptions.Create;
|
|
with CodeToolsOpts do
|
|
begin
|
|
OnAfterWrite := @DoCodetoolsOptionsAfterWrite;
|
|
SetLazarusDefaultFilename;
|
|
Load;
|
|
end;
|
|
|
|
CodeExplorerOptions := TCodeExplorerOptions.Create;
|
|
CodeExplorerOptions.OnAfterWrite := @DoCodeExplorerOptionsAfterWrite;
|
|
CodeExplorerOptions.Load;
|
|
|
|
DebuggerOptions := TDebuggerOptions.Create;
|
|
|
|
MainBuildBoss.SetupInputHistories;
|
|
CompileProgress.SetEnabled(EnvironmentOptions.ShowCompileDialog);
|
|
|
|
CreateDirUTF8(GetProjectSessionsConfigPath);
|
|
end;
|
|
|
|
constructor TMainIDE.Create(TheOwner: TComponent);
|
|
var
|
|
Layout: TSimpleWindowLayout;
|
|
FormCreator: TIDEWindowCreator;
|
|
begin
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.Create START');{$ENDIF}
|
|
inherited Create(TheOwner);
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.Create INHERITED');{$ENDIF}
|
|
|
|
FWaitForClose := False;
|
|
|
|
SetupDialogs;
|
|
RunExternalTool:=@OnRunExternalTool;
|
|
{$IFDEF UseAsyncProcess}
|
|
if Widgetset.GetLCLCapability(lcAsyncProcess) = 1 then
|
|
TOutputFilterProcess := TAsyncProcess
|
|
else
|
|
TOutputFilterProcess := TProcessUTF8;
|
|
{$ELSE}
|
|
TOutputFilterProcess := TProcessUTF8;
|
|
{$ENDIF}
|
|
|
|
MainBuildBoss:=TBuildManager.Create(nil);
|
|
MainBuildBoss.HasGUI:=true;
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.Create BUILD MANAGER');{$ENDIF}
|
|
|
|
// load options
|
|
CreatePrimaryConfigPath;
|
|
StartProtocol;
|
|
LoadGlobalOptions;
|
|
if EnvironmentOptions.SingleTaskBarButton then
|
|
Application.TaskBarBehavior := tbSingleButton;
|
|
|
|
// set the IDE mode to none (= editing mode)
|
|
ToolStatus:=itNone;
|
|
|
|
// setup macros
|
|
SetupTransferMacros;
|
|
SetupCodeMacros;
|
|
|
|
// setup the code tools
|
|
if not InitCodeToolBoss then begin
|
|
Application.Terminate;
|
|
exit;
|
|
end;
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.Create CODETOOLS');{$ENDIF}
|
|
|
|
// build and position the MainIDE form
|
|
Application.CreateForm(TMainIDEBar,MainIDEBar);
|
|
MainIDEBar.OnDestroy:=@OnMainBarDestroy;
|
|
MainIDEBar.OnActive:=@OnMainBarActive;
|
|
|
|
MainIDEBar.Constraints.MaxHeight:=110;
|
|
MainIDEBar.Name := NonModalIDEWindowNames[nmiwMainIDEName];
|
|
FormCreator:=IDEWindowCreators.Add(MainIDEBar.Name);
|
|
FormCreator.Right:='100%';
|
|
FormCreator.Bottom:='+90';
|
|
Layout:=IDEWindowCreators.SimpleLayoutStorage.ItemByFormID(MainIDEBar.Name);
|
|
if not (Layout.WindowState in [iwsNormal,iwsMaximized]) then
|
|
Layout.WindowState:=iwsNormal;
|
|
if IDEDockMaster<>nil then
|
|
IDEDockMaster.MakeIDEWindowDockSite(MainIDEBar);
|
|
|
|
HiddenWindowsOnRun:=TList.Create;
|
|
|
|
LastActivatedWindows:=TList.Create;
|
|
// menu
|
|
MainIDEBar.DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TMainIDE.Create'){$ENDIF};
|
|
try
|
|
SetupStandardIDEMenuItems;
|
|
SetupMainMenu;
|
|
SetupSpeedButtons;
|
|
SetupComponentPalette;
|
|
ConnectMainBarEvents;
|
|
finally
|
|
MainIDEBar.EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TMainIDE.Create'){$ENDIF};
|
|
end;
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.Create MENU');{$ENDIF}
|
|
|
|
// create main IDE register items
|
|
NewIDEItems:=TNewLazIDEItemCategories.Create;
|
|
|
|
SetupStandardProjectTypes;
|
|
|
|
// initialize the other IDE managers
|
|
DebugBoss:=TDebugManager.Create(nil);
|
|
DebugBoss.ConnectMainBarEvents;
|
|
DebuggerDlg.OnProcessCommand := @OnProcessIDECommand;
|
|
|
|
PkgBoss:=TPkgManager.Create(nil);
|
|
PkgBoss.ConnectMainBarEvents;
|
|
HelpBoss:=TIDEHelpManager.Create(nil);
|
|
HelpBoss.ConnectMainBarEvents;
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.Create MANAGERS');{$ENDIF}
|
|
// setup the IDE components
|
|
SetupOutputFilter;
|
|
MainBuildBoss.SetupCompilerInterface;
|
|
SetupObjectInspector;
|
|
SetupFormEditor;
|
|
SetupSourceNotebook;
|
|
SetupControlSelection;
|
|
SetupTextConverters;
|
|
// all IDE objects created => connect the events between them
|
|
LoadMenuShortCuts;
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.Create IDE COMPONENTS');{$ENDIF}
|
|
|
|
// load installed packages
|
|
PkgBoss.LoadInstalledPackages;
|
|
FormEditor1.RegisterFrame;
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.Create INSTALLED COMPONENTS');{$ENDIF}
|
|
|
|
// load package configs
|
|
HelpBoss.LoadHelpOptions;
|
|
|
|
UpdateWindowMenu(true);
|
|
end;
|
|
|
|
procedure TMainIDE.StartIDE;
|
|
begin
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.StartIDE START');{$ENDIF}
|
|
// set Application handlers
|
|
Application.AddOnUserInputHandler(@OnApplicationUserInput);
|
|
Application.AddOnIdleHandler(@OnApplicationIdle);
|
|
Application.AddOnActivateHandler(@OnApplicationActivate);
|
|
Application.AddOnDeActivateHandler(@OnApplicationDeActivate);
|
|
Application.AddOnKeyDownHandler(@OnApplicationKeyDown);
|
|
Application.AddOnDropFilesHandler(@OnApplicationDropFiles);
|
|
Application.AddOnQueryEndSessionHandler(@OnApplicationQueryEndSession);
|
|
Application.AddOnEndSessionHandler(@OnApplicationEndSession);
|
|
Screen.AddHandlerRemoveForm(@OnScreenRemoveForm);
|
|
SetupHints;
|
|
SetupIDEWindowsLayout;
|
|
RestoreIDEWindows;
|
|
// make sure the main IDE bar is always shown
|
|
IDEWindowCreators.ShowForm(MainIDEBar,false);
|
|
DebugBoss.UpdateButtonsAndMenuItems; // Disable Stop-button (and some others).
|
|
SetupStartProject; // Now load a project
|
|
DoShowMessagesView(false); // reopen extra windows
|
|
fUserInputSinceLastIdle:=true; // Idle work gets done initially before user action.
|
|
FApplicationIsActivate:=true;
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.StartIDE END');{$ENDIF}
|
|
end;
|
|
|
|
destructor TMainIDE.Destroy;
|
|
begin
|
|
ToolStatus:=itExiting;
|
|
|
|
DebugLn('[TMainIDE.Destroy] A ');
|
|
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.Destroy A ');{$ENDIF}
|
|
if Assigned(MainIDEBar) then
|
|
MainIDEBar.DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TMainIDE.Destroy'){$ENDIF};
|
|
|
|
if DebugBoss<>nil then DebugBoss.EndDebugging;
|
|
|
|
if TheControlSelection<>nil then begin
|
|
TheControlSelection.OnChange:=nil;
|
|
TheControlSelection.OnSelectionFormChanged:=nil;
|
|
end;
|
|
|
|
FreeAndNil(JumpHistoryViewWin);
|
|
FreeAndNil(ComponentListForm);
|
|
FreeThenNil(ProjInspector);
|
|
FreeThenNil(CodeExplorerView);
|
|
FreeThenNil(CodeBrowserView);
|
|
FreeAndNil(LazFindReplaceDialog);
|
|
FreeAndNil(MessagesView);
|
|
FreeThenNil(AnchorDesigner);
|
|
FreeThenNil(ObjectInspector1);
|
|
FreeThenNil(SourceEditorManagerIntf);
|
|
|
|
// disconnect handlers
|
|
Application.RemoveAllHandlersOfObject(Self);
|
|
Screen.RemoveAllHandlersOfObject(Self);
|
|
IDECommands.OnExecuteIDECommand:=nil;
|
|
TestCompilerOptions:=nil;
|
|
|
|
// free project, if it is still there
|
|
FreeThenNil(Project1);
|
|
|
|
// free IDE parts
|
|
FreeFormEditor;
|
|
FreeTextConverters;
|
|
FreeStandardIDEQuickFixItems;
|
|
FreeThenNil(GlobalDesignHook);
|
|
FreeThenNil(PkgBoss);
|
|
FreeThenNil(HelpBoss);
|
|
FreeThenNil(DebugBoss);
|
|
FreeThenNil(TheCompiler);
|
|
FreeThenNil(HiddenWindowsOnRun);
|
|
FreeThenNil(LastActivatedWindows);
|
|
FreeThenNil(IDEMsgScanners);
|
|
FreeThenNil(TheOutputFilter);
|
|
FreeThenNil(GlobalMacroList);
|
|
FreeThenNil(IDEMacros);
|
|
FreeThenNil(IDECodeMacros);
|
|
FreeThenNil(LazProjectFileDescriptors);
|
|
FreeThenNil(LazProjectDescriptors);
|
|
FreeThenNil(NewIDEItems);
|
|
FreeThenNil(IDEMenuRoots);
|
|
// IDE options objects
|
|
FreeThenNil(CodeToolsOpts);
|
|
FreeThenNil(CodeExplorerOptions);
|
|
FreeThenNil(MiscellaneousOptions);
|
|
FreeThenNil(EditorOpts);
|
|
FreeThenNil(DebuggerOptions);
|
|
FreeThenNil(EnvironmentOptions);
|
|
FreeThenNil(IDECommandScopes);
|
|
|
|
// free control selection
|
|
if TheControlSelection<>nil then
|
|
FreeThenNil(TheControlSelection);
|
|
|
|
DebugLn('[TMainIDE.Destroy] B -> inherited Destroy... ',ClassName);
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.Destroy B ');{$ENDIF}
|
|
FreeThenNil(MainBuildBoss);
|
|
inherited Destroy;
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.Destroy C ');{$ENDIF}
|
|
|
|
FreeThenNil(IDEProtocolOpts);
|
|
DebugLn('[TMainIDE.Destroy] END');
|
|
end;
|
|
|
|
procedure TMainIDE.CreateOftenUsedForms;
|
|
begin
|
|
MessagesView:=TMessagesView.Create(nil);
|
|
MessagesView.OnSelectionChanged := @MessagesViewSelectionChanged;
|
|
|
|
LazFindReplaceDialog:=TLazFindReplaceDialog.Create(nil);
|
|
end;
|
|
|
|
procedure TMainIDE.OIOnSelectPersistents(Sender: TObject);
|
|
begin
|
|
TheControlSelection.AssignSelection(ObjectInspector1.Selection);
|
|
GlobalDesignHook.SetSelection(ObjectInspector1.Selection);
|
|
end;
|
|
|
|
procedure TMainIDE.OIOnShowOptions(Sender: TObject);
|
|
begin
|
|
DoOpenIDEOptions(TOIOptionsFrame);
|
|
end;
|
|
|
|
procedure TMainIDE.OIOnViewRestricted(Sender: TObject);
|
|
var
|
|
C: TClass;
|
|
begin
|
|
C := nil;
|
|
if (ObjectInspector1.Selection <> nil) and
|
|
(ObjectInspector1.Selection.Count > 0) then
|
|
begin
|
|
C := ObjectInspector1.Selection[0].ClassType;
|
|
if C.InheritsFrom(TForm) then C := TForm
|
|
else
|
|
if C.InheritsFrom(TCustomForm) then C := TCustomForm
|
|
else
|
|
if C.InheritsFrom(TDataModule) then C := TDataModule
|
|
else
|
|
if C.InheritsFrom(TFrame) then C := TFrame;
|
|
end;
|
|
|
|
|
|
if ObjectInspector1.GetActivePropertyRow = nil then
|
|
begin
|
|
if C <> nil then
|
|
DoShowRestrictionBrowser(true,C.ClassName)
|
|
else
|
|
DoShowRestrictionBrowser(true);
|
|
end
|
|
else
|
|
begin
|
|
if C <> nil then
|
|
DoShowRestrictionBrowser(true,C.ClassName + '.' + ObjectInspector1.GetActivePropertyRow.Name)
|
|
else
|
|
DoShowRestrictionBrowser(true);
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OIOnDestroy(Sender: TObject);
|
|
begin
|
|
if ObjectInspector1=Sender then
|
|
ObjectInspector1:=nil;
|
|
end;
|
|
|
|
procedure TMainIDE.OIOnAutoShow(Sender: TObject);
|
|
begin
|
|
IDEWindowCreators.ShowForm(Sender as TObjectInspectorDlg,false);
|
|
end;
|
|
|
|
procedure TMainIDE.OIRemainingKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
begin
|
|
OnExecuteIDEShortCut(Sender,Key,Shift,nil);
|
|
end;
|
|
|
|
procedure TMainIDE.OIOnAddToFavourites(Sender: TObject);
|
|
begin
|
|
ShowAddRemoveFavouriteDialog(ObjectInspector1,true);
|
|
end;
|
|
|
|
procedure TMainIDE.OIOnRemoveFromFavourites(Sender: TObject);
|
|
begin
|
|
ShowAddRemoveFavouriteDialog(ObjectInspector1,false);
|
|
end;
|
|
|
|
procedure TMainIDE.OIOnFindDeclarationOfProperty(Sender: TObject);
|
|
var
|
|
AnInspector: TObjectInspectorDlg;
|
|
Code: TCodeBuffer;
|
|
Caret: TPoint;
|
|
NewTopLine: integer;
|
|
begin
|
|
if not BeginCodeTools then exit;
|
|
if Sender=nil then Sender:=ObjectInspector1;
|
|
if Sender is TObjectInspectorDlg then begin
|
|
AnInspector:=TObjectInspectorDlg(Sender);
|
|
if FindDeclarationOfOIProperty(AnInspector,nil,Code,Caret,NewTopLine) then
|
|
DoOpenFileAndJumpToPos(Code.Filename,Caret,NewTopLine,-1,-1,[]);
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OIOnSelectionChange(Sender: TObject);
|
|
begin
|
|
if not (Sender is TObjectInspectorDlg) then
|
|
Exit;
|
|
OIChangedTimer.AutoEnabled:=true;
|
|
end;
|
|
|
|
function TMainIDE.OIOnPropertyHint(Sender: TObject;
|
|
PointedRow: TOIPropertyGridRow; ScreenPos: TPoint; aHintWindow: THintWindow;
|
|
out HintWinRect: TRect; out AHint: string): boolean;
|
|
var
|
|
Code: TCodeBuffer;
|
|
Caret: TPoint;
|
|
NewTopLine: integer;
|
|
BaseURL: string;
|
|
begin
|
|
Result:=false;
|
|
AHint:='';
|
|
HintWinRect:=Rect(0,0,0,0);
|
|
if not BeginCodeTools then exit;
|
|
if FindDeclarationOfOIProperty(ObjectInspector1,PointedRow,Code,Caret,NewTopLine)
|
|
then begin
|
|
if TIDEHelpManager(HelpBoss).GetHintForSourcePosition(Code.Filename,
|
|
Caret,BaseURL,aHint)=shrSuccess
|
|
then begin
|
|
Result:=HelpBoss.CreateHint(aHintWindow,ScreenPos,BaseURL,aHint,HintWinRect);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OIOnUpdateRestricted(Sender: TObject);
|
|
begin
|
|
if Sender = nil then Sender := ObjectInspector1;
|
|
if Sender is TObjectInspectorDlg then
|
|
begin
|
|
(Sender as TObjectInspectorDlg).RestrictedProps := GetRestrictedProperties;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.OnPropHookGetMethodName(const Method: TMethod;
|
|
PropOwner: TObject): String;
|
|
var
|
|
JITMethod: TJITMethod;
|
|
LookupRoot: TPersistent;
|
|
begin
|
|
if Method.Code<>nil then begin
|
|
if Method.Data<>nil then begin
|
|
Result:=TObject(Method.Data).MethodName(Method.Code);
|
|
if Result='' then
|
|
Result:='<Unpublished>';
|
|
end else
|
|
Result:='<No LookupRoot>';
|
|
end else if IsJITMethod(Method) then begin
|
|
JITMethod:=TJITMethod(Method.Data);
|
|
Result:=JITMethod.TheMethodName;
|
|
if PropOwner is TComponent then begin
|
|
LookupRoot:=GetLookupRootForComponent(TComponent(PropOwner));
|
|
if LookupRoot is TComponent then begin
|
|
//DebugLn(['TMainIDE.OnPropHookGetMethodName ',Result,' GlobalDesignHook.LookupRoot=',dbgsName(GlobalDesignHook.LookupRoot),' JITMethod.TheClass=',dbgsName(JITMethod.TheClass),' PropOwner=',DbgSName(PropOwner),' PropOwner-LookupRoot=',DbgSName(LookupRoot)]);
|
|
if (LookupRoot.ClassType<>JITMethod.TheClass) then begin
|
|
Result:=JITMethod.TheClass.ClassName+'.'+Result;
|
|
end;
|
|
end;
|
|
end;
|
|
end else
|
|
Result:='';
|
|
{$IFDEF VerboseDanglingComponentEvents}
|
|
if IsJITMethod(Method) then
|
|
DebugLn(['TMainIDE.OnPropHookGetMethodName ',Result,' ',IsJITMethod(Method)]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TMainIDE.OnPropHookGetMethods(TypeData: PTypeData; Proc: TGetStrProc);
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[ctfSwitchToFormSource])
|
|
then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
DebugLn('');
|
|
DebugLn('[TMainIDE.OnPropHookGetMethods] ************');
|
|
{$ENDIF}
|
|
if not CodeToolBoss.GetCompatiblePublishedMethods(ActiveUnitInfo.Source,
|
|
ActiveUnitInfo.Component.ClassName,TypeData,Proc) then
|
|
begin
|
|
DoJumpToCodeToolBossError;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnPropHookGetCompatibleMethods(InstProp: PInstProp;
|
|
const Proc: TGetStrProc);
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[ctfSwitchToFormSource])
|
|
then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
DebugLn('');
|
|
DebugLn('[TMainIDE.OnPropHookGetCompatibleMethods] ************');
|
|
{$ENDIF}
|
|
if not CodeToolBoss.GetCompatiblePublishedMethods(ActiveUnitInfo.Source,
|
|
ActiveUnitInfo.Component.ClassName,
|
|
InstProp^.Instance,InstProp^.PropInfo^.Name,Proc) then
|
|
begin
|
|
DoJumpToCodeToolBossError;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.OnPropHookCompatibleMethodExists(const AMethodName: String;
|
|
InstProp: PInstProp; var MethodIsCompatible, MethodIsPublished,
|
|
IdentIsMethod: boolean): boolean;
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[ctfSwitchToFormSource]) then
|
|
Exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
WriteLn('');
|
|
WriteLn('[TMainIDE.OnPropHookCompatibleMethodExists] ************ ',AMethodName);
|
|
{$ENDIF}
|
|
Result := CodeToolBoss.PublishedMethodExists(ActiveUnitInfo.Source,
|
|
ActiveUnitInfo.Component.ClassName, AMethodName,
|
|
InstProp^.Instance, InstProp^.PropInfo^.Name,
|
|
MethodIsCompatible, MethodIsPublished, IdentIsMethod);
|
|
if CodeToolBoss.ErrorMessage <> '' then
|
|
begin
|
|
DoJumpToCodeToolBossError;
|
|
raise Exception.Create(lisUnableToFindMethod+' '+lisPleaseFixTheErrorInTheMessageWindow);
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------}
|
|
procedure TMainIDE.MainIDEFormClose(Sender: TObject;
|
|
var CloseAction: TCloseAction);
|
|
begin
|
|
DoCallNotifyHandler(lihtIDEClose);
|
|
SaveEnvironment;
|
|
if IDEDockMaster<>nil then
|
|
IDEDockMaster.CloseAll
|
|
else
|
|
CloseAllForms;
|
|
SaveIncludeLinks;
|
|
InputHistories.Save;
|
|
PkgBoss.SaveSettings;
|
|
if TheControlSelection<>nil then TheControlSelection.Clear;
|
|
FreeIDEWindows;
|
|
end;
|
|
|
|
procedure TMainIDE.MainIDEFormCloseQuery(Sender: TObject; var CanClose: boolean);
|
|
var
|
|
MsgResult: integer;
|
|
const IsClosing: Boolean = False;
|
|
begin
|
|
CanClose := True;
|
|
if IsClosing then Exit;
|
|
IsClosing := True;
|
|
CanClose := False;
|
|
FCheckingFilesOnDisk := True;
|
|
try
|
|
// stop debugging/compiling/...
|
|
if (ToolStatus = itExiting) or not DoResetToolStatus([rfInteractive, rfCloseOnDone]) then exit;
|
|
|
|
// check foreign windows
|
|
if not CloseQueryIDEWindows then exit;
|
|
|
|
// check packages
|
|
if PkgBoss.DoCloseAllPackageEditors<>mrOk then exit;
|
|
|
|
// check project
|
|
if SomethingOfProjectIsModified then begin
|
|
MsgResult:=QuestionDlg(lisProjectChanged,
|
|
Format(lisSaveChangesToProject, [Project1.GetTitleOrName]), mtConfirmation,
|
|
[mrYes, lisMenuSave, mrNoToAll, lisDiscardChanges,
|
|
mrAbort, lisDoNotCloseTheIDE],
|
|
0);
|
|
case MsgResult of
|
|
|
|
mrYes:
|
|
begin
|
|
MsgResult:=DoSaveProject([sfCanAbort]);
|
|
if MsgResult<>mrOk then begin
|
|
MsgResult:=IDEQuestionDialog(lisChangesWereNotSaved,
|
|
lisDoYouStillWantToQuit,
|
|
mtConfirmation, [mrOk, lisDiscardChangesAndQuit, mrAbort]);
|
|
end;
|
|
CanClose := MsgResult=mrOk;
|
|
if not CanClose then exit;
|
|
end;
|
|
|
|
mrCancel, mrAbort:
|
|
begin
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
CanClose:=(DoCloseProject <> mrAbort);
|
|
finally
|
|
IsClosing := False;
|
|
FCheckingFilesOnDisk:=false;
|
|
if not CanClose then
|
|
DoCheckFilesOnDisk(false);
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------}
|
|
procedure TMainIDE.SetupSpeedButtons;
|
|
|
|
function CreateButton(AToolBar: TToolBar; const AName, APixName: String;
|
|
const AOnClick: TNotifyEvent; const AHint: String): TToolButton;
|
|
begin
|
|
Result := TToolButton.Create(OwningComponent);
|
|
with Result do
|
|
begin
|
|
Name := AName;
|
|
Parent := AToolBar;
|
|
Enabled := True;
|
|
OnClick := AOnClick;
|
|
ImageIndex := IDEImages.LoadImage(16, APixName);
|
|
Hint := AHint;
|
|
end;
|
|
end;
|
|
|
|
function CreateDivider(AToolBar: TToolBar): TToolButton;
|
|
begin
|
|
Result := TToolButton.Create(OwningComponent);
|
|
with Result do
|
|
begin
|
|
Style := tbsDivider;
|
|
AutoSize := True;
|
|
Parent := AToolBar;
|
|
end;
|
|
end;
|
|
|
|
function CreateToolBar(AName: String): TToolBar;
|
|
begin
|
|
Result := TToolBar.Create(OwningComponent);
|
|
Result.Name := AName;
|
|
Result.Parent := MainIDEBar.pnlSpeedButtons;
|
|
Result.Images := IDEImages.Images_16;
|
|
Result.AutoSize := true;
|
|
end;
|
|
|
|
begin
|
|
MainIDEBar.pnlSpeedButtons := TPanel.Create(OwningComponent);
|
|
with MainIDEBar.pnlSpeedButtons do
|
|
begin
|
|
Name := 'pnlSpeedButtons';
|
|
Parent := MainIDEBar;
|
|
Align := alLeft;
|
|
Caption := '';
|
|
BevelOuter := bvNone;
|
|
AutoSize := true;
|
|
Visible := EnvironmentOptions.IDESpeedButtonsVisible;
|
|
end;
|
|
|
|
MainIDEBar.tbViewDebug := CreateToolBar('tbViewDebug');
|
|
MainIDEBar.tbStandard := CreateToolBar('tbStandard');
|
|
|
|
MainIDEBar.NewUnitSpeedBtn := CreateButton(MainIDEBar.tbStandard , 'NewUnitSpeedBtn' , 'item_unit' , @mnuNewUnitClicked, lisMenuNewUnit);
|
|
MainIDEBar.NewFormSpeedBtn := CreateButton(MainIDEBar.tbStandard , 'NewFormSpeedBtn' , 'item_form' , @mnuNewFormClicked, lisMenuNewForm);
|
|
MainIDEBar.tbDivider1 := CreateDivider(MainIDEBar.tbStandard);
|
|
MainIDEBar.OpenFileSpeedBtn := CreateButton(MainIDEBar.tbStandard , 'OpenFileSpeedBtn' , 'laz_open' , @mnuOpenClicked, lisHintOpen);
|
|
MainIDEBar.SaveSpeedBtn := CreateButton(MainIDEBar.tbStandard , 'SaveSpeedBtn' , 'laz_save' , @mnuSaveClicked, lisHintSave);
|
|
MainIDEBar.SaveAllSpeedBtn := CreateButton(MainIDEBar.tbStandard , 'SaveAllSpeedBtn' , 'menu_save_all' , @mnuSaveAllClicked, lisHintSaveAll);
|
|
MainIDEBar.tbDivider2 := CreateDivider(MainIDEBar.tbStandard);
|
|
MainIDEBar.ToggleFormSpeedBtn := CreateButton(MainIDEBar.tbStandard , 'ToggleFormSpeedBtn' , 'menu_view_toggle_form_unit', @mnuToggleFormUnitCLicked, lisHintToggleFormUnit);
|
|
|
|
MainIDEBar.ViewUnitsSpeedBtn := CreateButton(MainIDEBar.tbViewDebug, 'ViewUnitsSpeedBtn' , 'menu_view_units' , @mnuViewUnitsClicked, lisHintViewUnits);
|
|
MainIDEBar.ViewFormsSpeedBtn := CreateButton(MainIDEBar.tbViewDebug, 'ViewFormsSpeedBtn' , 'menu_view_forms' , @mnuViewFormsClicked, lisHintViewForms);
|
|
MainIDEBar.tbDivider3 := CreateDivider(MainIDEBar.tbViewDebug);
|
|
MainIDEBar.BuildModeSpeedButton:= CreateButton(MainIDEBar.tbViewDebug, 'BuildModeSpeedButton', 'menu_compiler_options' , @mnuChgBuildModeClicked, lisChangeBuildMode);
|
|
MainIDEBar.RunSpeedButton := CreateButton(MainIDEBar.tbViewDebug, 'RunSpeedButton' , 'menu_run' , @mnuRunProjectClicked, lisHintRun);
|
|
MainIDEBar.PauseSpeedButton := CreateButton(MainIDEBar.tbViewDebug, 'PauseSpeedButton' , 'menu_pause' , @mnuPauseProjectClicked, lisHintPause);
|
|
MainIDEBar.StopSpeedButton := CreateButton(MainIDEBar.tbViewDebug, 'StopSpeedButton' , 'menu_stop' , @mnuStopProjectClicked, lisHintStop);
|
|
MainIDEBar.StepIntoSpeedButton := CreateButton(MainIDEBar.tbViewDebug, 'StepIntoSpeedButton', 'menu_stepinto' , @mnuStepIntoProjectClicked, lisHintStepInto);
|
|
MainIDEBar.StepOverSpeedButton := CreateButton(MainIDEBar.tbViewDebug, 'StepOverpeedButton' , 'menu_stepover' , @mnuStepOverProjectClicked, lisHintStepOver);
|
|
MainIDEBar.StepOutSpeedButton := CreateButton(MainIDEBar.tbViewDebug, 'StepOutSpeedButton' , 'menu_stepout' , @mnuStepOutProjectClicked, lisHintStepOut);
|
|
|
|
MainIDEBar.CreatePopupMenus(OwningComponent);
|
|
|
|
MainIDEBar.OpenFileSpeedBtn.Style := tbsDropDown;
|
|
MainIDEBar.OpenFileSpeedBtn.DropDownMenu := MainIDEBar.OpenFilePopUpMenu;
|
|
MainIDEBar.OpenFilePopupMenu.OnPopup := @OpenFilePopupMenuPopup;
|
|
|
|
MainIDEBar.BuildModeSpeedButton.Style:=tbsDropDown;
|
|
MainIDEBar.BuildModeSpeedButton.DropdownMenu:=MainIDEBar.SetBuildModePopupMenu;
|
|
MainIDEBar.SetBuildModePopupMenu.OnPopup := @SetBuildModePopupMenuPopup;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupDialogs;
|
|
begin
|
|
LazIDESelectDirectory:=@OnSelectDirectory;
|
|
InitIDEFileDialog:=@OnInitIDEFileDialog;
|
|
StoreIDEFileDialog:=@OnStoreIDEFileDialog;
|
|
IDEMessageDialog:=@OnIDEMessageDialog;
|
|
IDEQuestionDialog:=@OnIDEQuestionDialog;
|
|
TestCompilerOptions:=@OnCompilerOptionsDialogTest;
|
|
CheckCompOptsAndMainSrcForNewUnitEvent:=@OnCheckCompOptsAndMainSrcForNewUnit;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupComponentPalette;
|
|
begin
|
|
// Component palette
|
|
MainIDEBar.ComponentPageControl := TPageControl.Create(OwningComponent);
|
|
with MainIDEBar.ComponentPageControl do begin
|
|
Name := 'ComponentPageControl';
|
|
Align := alClient;
|
|
Visible:=EnvironmentOptions.ComponentPaletteVisible;
|
|
Parent := MainIDEBar;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupHints;
|
|
var
|
|
CurShowHint: boolean;
|
|
AControl: TControl;
|
|
i, j: integer;
|
|
begin
|
|
if EnvironmentOptions=nil then exit;
|
|
// update all hints in the component palette
|
|
CurShowHint:=EnvironmentOptions.ShowHintsForComponentPalette;
|
|
for i:=0 to MainIDEBar.ComponentPageControl.PageCount-1 do begin
|
|
for j:=0 to MainIDEBar.ComponentPageControl.Page[i].ControlCount-1 do begin
|
|
AControl:=MainIDEBar.ComponentPageControl.Page[i].Controls[j];
|
|
AControl.ShowHint:=CurShowHint;
|
|
end;
|
|
end;
|
|
// update all hints in main ide toolbars
|
|
CurShowHint:=EnvironmentOptions.ShowHintsForMainSpeedButtons;
|
|
for i:=0 to MainIDEBar.pnlSpeedButtons.ControlCount-1 do begin
|
|
AControl:=MainIDEBar.pnlSpeedButtons.Controls[i];
|
|
AControl.ShowHint:=CurShowHint;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupOutputFilter;
|
|
begin
|
|
TheOutputFilter:=TOutputFilter.Create;
|
|
TheOutputFilter.OnGetIncludePath:=@CodeToolBoss.GetIncludePathForDirectory;
|
|
IDEMsgScanners:=TMessageScanners.Create;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupObjectInspector;
|
|
begin
|
|
GlobalDesignHook:=TPropertyEditorHook.Create;
|
|
GlobalDesignHook.GetPrivateDirectory:=AppendPathDelim(GetPrimaryConfigPath);
|
|
GlobalDesignHook.AddHandlerGetMethodName(@OnPropHookGetMethodName);
|
|
GlobalDesignHook.AddHandlerGetCompatibleMethods(@OnPropHookGetCompatibleMethods);
|
|
GlobalDesignHook.AddHandlerGetMethods(@OnPropHookGetMethods);
|
|
GlobalDesignHook.AddHandlerCompatibleMethodExists(@OnPropHookCompatibleMethodExists);
|
|
GlobalDesignHook.AddHandlerMethodExists(@OnPropHookMethodExists);
|
|
GlobalDesignHook.AddHandlerCreateMethod(@OnPropHookCreateMethod);
|
|
GlobalDesignHook.AddHandlerShowMethod(@OnPropHookShowMethod);
|
|
GlobalDesignHook.AddHandlerRenameMethod(@OnPropHookRenameMethod);
|
|
GlobalDesignHook.AddHandlerBeforeAddPersistent(@OnPropHookBeforeAddPersistent);
|
|
GlobalDesignHook.AddHandlerComponentRenamed(@OnPropHookComponentRenamed);
|
|
GlobalDesignHook.AddHandlerModified(@OnPropHookModified);
|
|
GlobalDesignHook.AddHandlerPersistentAdded(@OnPropHookPersistentAdded);
|
|
GlobalDesignHook.AddHandlerPersistentDeleting(@OnPropHookPersistentDeleting);
|
|
GlobalDesignHook.AddHandlerDeletePersistent(@OnPropHookDeletePersistent);
|
|
GlobalDesignHook.AddHandlerObjectPropertyChanged(@OnPropHookObjectPropertyChanged);
|
|
GlobalDesignHook.AddHandlerGetComponentNames(@OnPropHookGetComponentNames);
|
|
GlobalDesignHook.AddHandlerGetComponent(@OnPropHookGetComponent);
|
|
|
|
IDECmdScopeObjectInspectorOnly.AddWindowClass(TObjectInspectorDlg);
|
|
|
|
ObjectInspector1 := TObjectInspectorDlg.Create(OwningComponent);
|
|
ObjectInspector1.Name:=DefaultObjectInspectorName;
|
|
ObjectInspector1.ShowFavorites:=True;
|
|
ObjectInspector1.ShowRestricted:=True;
|
|
ObjectInspector1.Favourites:=LoadOIFavouriteProperties;
|
|
ObjectInspector1.FindDeclarationPopupmenuItem.Visible:=true;
|
|
ObjectInspector1.OnAddToFavourites:=@OIOnAddToFavourites;
|
|
ObjectInspector1.OnFindDeclarationOfProperty:=@OIOnFindDeclarationOfProperty;
|
|
ObjectInspector1.OnUpdateRestricted := @OIOnUpdateRestricted;
|
|
ObjectInspector1.OnRemainingKeyDown:=@OIRemainingKeyDown;
|
|
ObjectInspector1.OnRemoveFromFavourites:=@OIOnRemoveFromFavourites;
|
|
ObjectInspector1.OnSelectPersistentsInOI:=@OIOnSelectPersistents;
|
|
ObjectInspector1.OnShowOptions:=@OIOnShowOptions;
|
|
ObjectInspector1.OnViewRestricted:=@OIOnViewRestricted;
|
|
ObjectInspector1.OnSelectionChange:=@OIOnSelectionChange;
|
|
ObjectInspector1.OnPropertyHint:=@OIOnPropertyHint;
|
|
ObjectInspector1.OnDestroy:=@OIOnDestroy;
|
|
ObjectInspector1.OnAutoShow:=@OIOnAutoShow;
|
|
ObjectInspector1.PropertyEditorHook:=GlobalDesignHook;
|
|
|
|
// after OI changes the hints needs to be updated
|
|
// do that after some idle time
|
|
OIChangedTimer:=TIdleTimer.Create(OwningComponent);
|
|
with OIChangedTimer do begin
|
|
Name:='OIChangedTimer';
|
|
Interval:=400;
|
|
OnTimer:=@OIChangedTimerTimer;
|
|
end;
|
|
|
|
IDEWindowCreators.Add(ObjectInspector1.Name,nil,@CreateIDEWindow,
|
|
'0','120','+230','-120','',alNone,false,@OnGetLayout);
|
|
|
|
EnvironmentOptions.ObjectInspectorOptions.AssignTo(ObjectInspector1);
|
|
ShowAnchorDesigner:=@mnuViewAnchorEditorClicked;
|
|
ShowTabOrderEditor:=@mnuViewTabOrderClicked;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupFormEditor;
|
|
begin
|
|
CreateFormEditor;
|
|
FormEditor1.Obj_Inspector := ObjectInspector1;
|
|
FormEditor1.OnSelectFrame := @OnSelectFrame;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupSourceNotebook;
|
|
begin
|
|
TSourceEditorManager.Create(OwningComponent);
|
|
SourceEditorManager.RegisterChangeEvent(semWindowFocused, @OnSrcNoteBookActivated);
|
|
SourceEditorManager.OnAddJumpPoint := @OnSrcNoteBookAddJumpPoint;
|
|
SourceEditorManager.OnCloseClicked := @OnSrcNotebookFileClose;
|
|
SourceEditorManager.OnClickLink := @OnSrcNoteBookClickLink;
|
|
SourceEditorManager.OnMouseLink := @OnSrcNoteBookMouseLink;
|
|
SourceEditorManager.OnGetIndent := @OnSrcNoteBookGetIndent;
|
|
SourceEditorManager.OnCurrentCodeBufferChanged:=@OnSrcNotebookCurCodeBufferChanged;
|
|
SourceEditorManager.OnDeleteLastJumpPoint := @OnSrcNotebookDeleteLastJumPoint;
|
|
SourceEditorManager.RegisterChangeEvent(semEditorActivate, @OnSrcNotebookEditorActived);
|
|
SourceEditorManager.RegisterChangeEvent(semEditorStatus, @OnSrcNotebookEditorChanged);
|
|
SourceEditorManager.OnEditorMoved := @OnSrcNotebookEditorMoved;
|
|
SourceEditorManager.RegisterChangeEvent(semEditorDestroy, @OnSrcNotebookEditorClosed);
|
|
SourceEditorManager.OnPlaceBookmark := @OnSrcNotebookEditorPlaceBookmark;
|
|
SourceEditorManager.OnClearBookmark := @OnSrcNotebookEditorClearBookmark;
|
|
SourceEditorManager.OnSetBookmark := @OnSrcNotebookEditorDoSetBookmark;
|
|
SourceEditorManager.OnGotoBookmark := @OnSrcNotebookEditorDoGotoBookmark;
|
|
SourceEditorManager.OnEditorPropertiesClicked := @mnuEnvEditorOptionsClicked;
|
|
SourceEditorManager.OnFindDeclarationClicked := @OnSrcNotebookFindDeclaration;
|
|
SourceEditorManager.OnInitIdentCompletion :=@OnSrcNotebookInitIdentCompletion;
|
|
SourceEditorManager.OnShowCodeContext :=@OnSrcNotebookShowCodeContext;
|
|
SourceEditorManager.OnJumpToHistoryPoint := @OnSrcNotebookJumpToHistoryPoint;
|
|
SourceEditorManager.OnOpenFileAtCursorClicked := @OnSrcNotebookFileOpenAtCursor;
|
|
SourceEditorManager.OnProcessUserCommand := @OnProcessIDECommand;
|
|
SourceEditorManager.OnReadOnlyChanged := @OnSrcNotebookReadOnlyChanged;
|
|
SourceEditorManager.OnShowHintForSource := @OnSrcNotebookShowHintForSource;
|
|
SourceEditorManager.OnShowUnitInfo := @OnSrcNoteBookShowUnitInfo;
|
|
SourceEditorManager.OnToggleFormUnitClicked := @OnSrcNotebookToggleFormUnit;
|
|
SourceEditorManager.OnToggleObjectInspClicked:= @OnSrcNotebookToggleObjectInsp;
|
|
SourceEditorManager.OnViewJumpHistory := @OnSrcNotebookViewJumpHistory;
|
|
SourceEditorManager.OnPopupMenu := @OnSrcNoteBookPopupMenu;
|
|
SourceEditorManager.OnNoteBookCloseQuery := @OnSrcNoteBookCloseQuery;
|
|
DebugBoss.ConnectSourceNotebookEvents;
|
|
|
|
OnSearchResultsViewSelectionChanged := @SearchResultsViewSelectionChanged;
|
|
OnSearchAgainClicked := @FindInFilesDialog.InitFromLazSearch;
|
|
|
|
// connect search menu to sourcenotebook
|
|
MainIDEBar.itmSearchFind.OnClick := @SourceEditorManager.FindClicked;
|
|
MainIDEBar.itmSearchFindNext.OnClick := @SourceEditorManager.FindNextClicked;
|
|
MainIDEBar.itmSearchFindPrevious.OnClick := @SourceEditorManager.FindPreviousClicked;
|
|
MainIDEBar.itmSearchFindInFiles.OnClick := @mnuSearchFindInFiles;
|
|
MainIDEBar.itmSearchReplace.OnClick := @SourceEditorManager.ReplaceClicked;
|
|
MainIDEBar.itmIncrementalFind.OnClick := @SourceEditorManager.IncrementalFindClicked;
|
|
MainIDEBar.itmGotoLine.OnClick := @SourceEditorManager.GotoLineClicked;
|
|
MainIDEBar.itmJumpBack.OnClick := @SourceEditorManager.JumpBackClicked;
|
|
MainIDEBar.itmJumpForward.OnClick := @SourceEditorManager.JumpForwardClicked;
|
|
MainIDEBar.itmAddJumpPoint.OnClick := @SourceEditorManager.AddJumpPointClicked;
|
|
MainIDEBar.itmJumpHistory.OnClick := @SourceEditorManager.ViewJumpHistoryClicked;
|
|
MainIDEBar.itmJumpToNextBookmark.OnClick := @SourceEditorManager.BookMarkNextClicked;
|
|
MainIDEBar.itmJumpToPrevBookmark.OnClick := @SourceEditorManager.BookMarkPrevClicked;
|
|
MainIDEBar.itmFindBlockStart.OnClick:=@mnuSearchFindBlockStart;
|
|
MainIDEBar.itmFindBlockOtherEnd.OnClick:=@mnuSearchFindBlockOtherEnd;
|
|
MainIDEBar.itmFindDeclaration.OnClick:=@mnuSearchFindDeclaration;
|
|
MainIDEBar.itmOpenFileAtCursor.OnClick:=@mnuOpenFileAtCursorClicked;
|
|
|
|
SourceEditorManager.InitMacros(GlobalMacroList);
|
|
end;
|
|
|
|
procedure TMainIDE.SetupTransferMacros;
|
|
begin
|
|
MainBuildBoss.SetupTransferMacros;
|
|
GlobalMacroList.OnSubstitution:=@OnMacroSubstitution;
|
|
|
|
// source editor
|
|
GlobalMacroList.Add(TTransferMacro.Create('Save','',
|
|
lisSaveCurrentEditorFile,nil,[tmfInteractive]));
|
|
GlobalMacroList.Add(TTransferMacro.Create('SaveAll','',
|
|
lisSaveAllModified,nil,[tmfInteractive]));
|
|
end;
|
|
|
|
procedure TMainIDE.SetupCodeMacros;
|
|
begin
|
|
CreateStandardCodeMacros;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupControlSelection;
|
|
begin
|
|
TheControlSelection:=TControlSelection.Create;
|
|
TheControlSelection.OnChange:=@OnControlSelectionChanged;
|
|
TheControlSelection.OnPropertiesChanged:=@OnControlSelectionPropsChanged;
|
|
TheControlSelection.OnSelectionFormChanged:=@OnControlSelectionFormChanged;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupIDECommands;
|
|
begin
|
|
IDECommandList:=EditorOpts.KeyMap;
|
|
IDECommands.OnExecuteIDECommand:=@OnExecuteIDECommand;
|
|
IDECommands.OnExecuteIDEShortCut:=@OnExecuteIDEShortCut;
|
|
CreateStandardIDECommandScopes;
|
|
IDECmdScopeSrcEdit.AddWindowClass(TSourceEditorWindowInterface);
|
|
IDECmdScopeSrcEdit.AddWindowClass(nil);
|
|
IDECmdScopeSrcEditOnly.AddWindowClass(TSourceEditorWindowInterface);
|
|
|
|
IDECmdScopeSrcEditOnlyTmplEdit.AddWindowClass(TLazSynPluginTemplateEditForm);
|
|
IDECmdScopeSrcEditOnlyTmplEditOff.AddWindowClass(TLazSynPluginTemplateEditFormOff);
|
|
|
|
IDECmdScopeSrcEditOnlySyncroEditSel.AddWindowClass(TLazSynPluginSyncroEditFormSel);
|
|
IDECmdScopeSrcEditOnlySyncroEdit.AddWindowClass(TLazSynPluginSyncroEditForm);
|
|
IDECmdScopeSrcEditOnlySyncroEditOff.AddWindowClass(TLazSynPluginSyncroEditFormOff);
|
|
|
|
EditorOpts.KeyMap.CreateDefaultMapping;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupIDEMsgQuickFixItems;
|
|
begin
|
|
InitStandardIDEQuickFixItems;
|
|
InitCodeBrowserQuickFixItems;
|
|
InitFindUnitQuickFixItems;
|
|
InitInspectChecksumChangedQuickFixItems;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupStartProject;
|
|
|
|
function AskIfLoadLastFailingProject: boolean;
|
|
begin
|
|
debugln(['AskIfLoadLastFailingProject START']);
|
|
Result:=QuestionDlg(lisOpenProject2,
|
|
Format(lisAnErrorOccuredAtLastStartupWhileLoadingLoadThisPro, [
|
|
EnvironmentOptions.LastSavedProjectFile, #13, #13]), mtWarning,
|
|
[mrYes, lisOpenProjectAgain, mrNoToAll, lisStartWithANewProject], 0)=
|
|
mrYes;
|
|
debugln(['AskIfLoadLastFailingProject END ',dbgs(Result)]);
|
|
end;
|
|
|
|
var
|
|
ProjectLoaded: Boolean;
|
|
AProjectFilename: String;
|
|
CmdLineFiles: TStrings;
|
|
i: Integer;
|
|
OpenFlags: TOpenFlags;
|
|
AFilename: String;
|
|
begin
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TMainIDE.SetupStartProject A ***********');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.SetupStartProject A');{$ENDIF}
|
|
// load command line project or last project or create a new project
|
|
CmdLineFiles:=ExtractCmdLineFilenames;
|
|
try
|
|
ProjectLoaded:=false;
|
|
|
|
// try command line project
|
|
if (CmdLineFiles<>nil) and (CmdLineFiles.Count>0) then begin
|
|
AProjectFilename:=CmdLineFiles[0];
|
|
if (CompareFileExt(AProjectFilename,'.lpr',false)=0) then
|
|
AProjectFilename:=ChangeFileExt(AProjectFilename,'.lpi');
|
|
// only try to load .lpi files, other files are loaded later
|
|
if (CompareFileExt(AProjectFilename,'.lpi',false)=0) then begin
|
|
AProjectFilename:=CleanAndExpandFilename(AProjectFilename);
|
|
if FileExistsUTF8(AProjectFilename) then begin
|
|
CmdLineFiles.Delete(0);
|
|
ProjectLoaded:=(DoOpenProjectFile(AProjectFilename,[])=mrOk);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// try loading last project if lazarus didn't fail last time
|
|
if (not ProjectLoaded)
|
|
and (not SkipAutoLoadingLastProject)
|
|
and (EnvironmentOptions.OpenLastProjectAtStart)
|
|
and (FileExistsUTF8(EnvironmentOptions.LastSavedProjectFile)) then begin
|
|
if (not IDEProtocolOpts.LastProjectLoadingCrashed)
|
|
or AskIfLoadLastFailingProject then begin
|
|
// protocol that the IDE is trying to load the last project and did not
|
|
// yet succeed
|
|
IDEProtocolOpts.LastProjectLoadingCrashed := True;
|
|
IDEProtocolOpts.Save;
|
|
// try loading the project
|
|
ProjectLoaded:=
|
|
(DoOpenProjectFile(EnvironmentOptions.LastSavedProjectFile,[])=mrOk);
|
|
// protocol that the IDE was able to open the project without crashing
|
|
IDEProtocolOpts.LastProjectLoadingCrashed := false;
|
|
IDEProtocolOpts.Save;
|
|
if not ProjectLoaded then begin
|
|
DoCloseProject;
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.SetupStartProject B');{$ENDIF}
|
|
|
|
if not ProjectLoaded then
|
|
// create new project
|
|
DoNewProject(ProjectDescriptorApplication);
|
|
|
|
UpdateWindowMenu(true);
|
|
|
|
// load the cmd line files
|
|
if CmdLineFiles<>nil then begin
|
|
for i:=0 to CmdLineFiles.Count-1 do
|
|
Begin
|
|
AFilename:=CleanAndExpandFilename(CmdLineFiles.Strings[i]);
|
|
if CompareFileExt(AFilename,'.lpk',false)=0 then begin
|
|
if PkgBoss.DoOpenPackageFile(AFilename,[pofAddToRecent,pofMultiOpen],true)
|
|
=mrAbort
|
|
then
|
|
break;
|
|
end else begin
|
|
OpenFlags:=[ofAddToRecent,ofRegularFile];
|
|
if i<CmdLineFiles.Count then
|
|
Include(OpenFlags,ofMultiOpen);
|
|
if DoOpenEditorFile(AFilename,-1,-1,OpenFlags)=mrAbort then begin
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TMainIDE.Create B');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.SetupStartProject C');{$ENDIF}
|
|
finally
|
|
CmdLineFiles.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupRemoteControl;
|
|
var
|
|
Filename: String;
|
|
begin
|
|
debugln(['TMainIDE.SetupRemoteControl ']);
|
|
// delete old remote commands
|
|
Filename:=GetRemoteControlFilename;
|
|
if FileExistsUTF8(Filename) then
|
|
DeleteFileUTF8(Filename);
|
|
// start timer
|
|
FRemoteControlTimer:=TTimer.Create(OwningComponent);
|
|
FRemoteControlTimer.Interval:=500;
|
|
FRemoteControlTimer.OnTimer:=@OnRemoteControlTimer;
|
|
FRemoteControlTimer.Enabled:=true;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupIDEWindowsLayout;
|
|
begin
|
|
IDEWindowCreators.Add(NonModalIDEWindowNames[nmiwMessagesViewName],
|
|
nil,@CreateIDEWindow,'250','75%','+70%','+100',
|
|
NonModalIDEWindowNames[nmiwSourceNoteBookName],alBottom,false,@OnGetLayout);
|
|
IDEWindowCreators.Add(NonModalIDEWindowNames[nmiwCodeExplorerName],
|
|
nil,@CreateIDEWindow,'72%','120','+170','-200',
|
|
NonModalIDEWindowNames[nmiwSourceNoteBookName],alRight);
|
|
|
|
IDEWindowCreators.Add(NonModalIDEWindowNames[nmiwUnitDependenciesName],
|
|
nil,@CreateIDEWindow,'200','200','','');
|
|
IDEWindowCreators.Add(NonModalIDEWindowNames[nmiwFPDocEditorName],
|
|
nil,@CreateIDEWindow,'250','75%','+70%','+120');
|
|
//IDEWindowCreators.Add(NonModalIDEWindowNames[nmiwClipbrdHistoryName],
|
|
// nil,@CreateIDEWindow,'250','200','','');
|
|
IDEWindowCreators.Add(NonModalIDEWindowNames[nmiwProjectInspector],
|
|
nil,@CreateIDEWindow,'200','150','+300','+400');
|
|
IDEWindowCreators.Add(NonModalIDEWindowNames[nmiwSearchResultsViewName],
|
|
nil,@CreateIDEWindow,'250','250','+70%','+300');
|
|
IDEWindowCreators.Add(NonModalIDEWindowNames[nmiwAnchorEditor],
|
|
nil,@CreateIDEWindow,'250','250','','');
|
|
IDEWindowCreators.Add(NonModalIDEWindowNames[nmiwTabOrderEditor],
|
|
nil,@CreateIDEWindow,'270','270','','');
|
|
IDEWindowCreators.Add(NonModalIDEWindowNames[nmiwCodeBrowser],
|
|
nil,@CreateIDEWindow,'200','200','+650','+500');
|
|
IDEWindowCreators.Add(NonModalIDEWindowNames[nmiwIssueBrowser],
|
|
nil,@CreateIDEWindow,'250','250','','');
|
|
IDEWindowCreators.Add(NonModalIDEWindowNames[nmiwJumpHistory],
|
|
nil,@CreateIDEWindow,'250','250','','');
|
|
IDEWindowCreators.Add(ComponentListFormName,
|
|
nil,@CreateIDEWindow,'250','250','','');
|
|
end;
|
|
|
|
procedure TMainIDE.RestoreIDEWindows;
|
|
begin
|
|
DoCallNotifyHandler(lihtIDERestoreWindows);
|
|
if IDEDockMaster=nil then
|
|
IDEWindowCreators.RestoreSimpleLayout;
|
|
end;
|
|
|
|
procedure TMainIDE.FreeIDEWindows;
|
|
var
|
|
i: Integer;
|
|
AForm: TCustomForm;
|
|
begin
|
|
i:=Screen.CustomFormCount-1;
|
|
while i>=0 do begin
|
|
AForm:=Screen.CustomForms[i];
|
|
if (AForm<>MainIDEBar)
|
|
and ((AForm.Owner=MainIDEBar) or (AForm.Owner=Self)) then begin
|
|
DebugLn(['TMainIDE.FreeIDEWindows ',dbgsName(AForm)]);
|
|
AForm.Free;
|
|
end;
|
|
i:=Math.Min(i,Screen.CustomFormCount)-1;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.CloseQueryIDEWindows: boolean;
|
|
var
|
|
i: Integer;
|
|
AForm: TCustomForm;
|
|
begin
|
|
for i:=0 to Screen.CustomFormCount-1 do begin
|
|
AForm:=Screen.CustomForms[i];
|
|
if AForm<>MainIDEBar then begin
|
|
if not AForm.CloseQuery then exit(false);
|
|
end;
|
|
end;
|
|
Result:=true;
|
|
end;
|
|
|
|
procedure TMainIDE.ReloadMenuShortCuts;
|
|
begin
|
|
//LoadMenuShortCuts;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------}
|
|
procedure TMainIDE.SetupMainMenu;
|
|
begin
|
|
inherited SetupMainMenu;
|
|
mnuMain.MenuItem:=MainIDEBar.mnuMainMenu.Items;
|
|
SetupFileMenu;
|
|
SetupEditMenu;
|
|
SetupSearchMenu;
|
|
SetupViewMenu;
|
|
SetupSourceMenu;
|
|
SetupProjectMenu;
|
|
SetupRunMenu;
|
|
SetupPackageMenu;
|
|
SetupToolsMenu;
|
|
SetupWindowsMenu;
|
|
SetupHelpMenu;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupStandardIDEMenuItems;
|
|
begin
|
|
IDEMenuRoots:=TIDEMenuRoots.Create;
|
|
RegisterStandardSourceEditorMenuItems;
|
|
RegisterStandardMessagesViewMenuItems;
|
|
RegisterStandardCodeExplorerMenuItems;
|
|
RegisterStandardCodeTemplatesMenuItems;
|
|
RegisterStandardDesignerMenuItems;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupStandardProjectTypes;
|
|
begin
|
|
NewIDEItems.Add(TNewLazIDEItemCategoryFile.Create(FileDescGroupName));
|
|
NewIDEItems.Add(TNewLazIDEItemCategoryInheritedItem.Create(InheritedItemsGroupName));
|
|
NewIDEItems.Add(TNewLazIDEItemCategoryProject.Create(ProjDescGroupName));
|
|
|
|
// file descriptors
|
|
LazProjectFileDescriptors:=TLazProjectFileDescriptors.Create;
|
|
LazProjectFileDescriptors.DefaultPascalFileExt:=
|
|
PascalExtension[EnvironmentOptions.PascalFileExtension];
|
|
RegisterProjectFileDescriptor(TFileDescPascalUnit.Create);
|
|
RegisterProjectFileDescriptor(TFileDescPascalUnitWithForm.Create);
|
|
RegisterProjectFileDescriptor(TFileDescPascalUnitWithDataModule.Create);
|
|
RegisterProjectFileDescriptor(TFileDescPascalUnitWithFrame.Create);
|
|
RegisterProjectFileDescriptor(TFileDescSimplePascalProgram.Create);
|
|
RegisterProjectFileDescriptor(TFileDescText.Create);
|
|
|
|
RegisterProjectFileDescriptor(TFileDescInheritedComponent.Create, InheritedItemsGroupName);
|
|
|
|
// project descriptors
|
|
LazProjectDescriptors:=TLazProjectDescriptors.Create;
|
|
RegisterProjectDescriptor(TProjectApplicationDescriptor.Create);
|
|
RegisterProjectDescriptor(TProjectProgramDescriptor.Create);
|
|
RegisterProjectDescriptor(TProjectConsoleApplicationDescriptor.Create);
|
|
RegisterProjectDescriptor(TProjectLibraryDescriptor.Create);
|
|
RegisterProjectDescriptor(TProjectManualProgramDescriptor.Create);
|
|
end;
|
|
|
|
procedure TMainIDE.SetRecentFilesMenu;
|
|
begin
|
|
SetRecentSubMenu(itmFileRecentOpen,
|
|
EnvironmentOptions.RecentOpenFiles,
|
|
@mnuOpenRecentClicked);
|
|
end;
|
|
|
|
procedure TMainIDE.SetRecentProjectFilesMenu;
|
|
begin
|
|
SetRecentSubMenu(itmProjectRecentOpen,
|
|
EnvironmentOptions.RecentProjectFiles,
|
|
@mnuOpenProjectClicked);
|
|
end;
|
|
|
|
procedure TMainIDE.SetupFileMenu;
|
|
begin
|
|
inherited SetupFileMenu;
|
|
mnuFile.OnClick:=@mnuFileClicked;
|
|
with MainIDEBar do begin
|
|
itmFileNewUnit.OnClick := @mnuNewUnitClicked;
|
|
itmFileNewForm.OnClick := @mnuNewFormClicked;
|
|
itmFileNewOther.OnClick := @mnuNewOtherClicked;
|
|
itmFileOpen.OnClick := @mnuOpenClicked;
|
|
itmFileRevert.OnClick := @mnuRevertClicked;
|
|
SetRecentFilesMenu;
|
|
itmFileSave.OnClick := @mnuSaveClicked;
|
|
itmFileSaveAs.OnClick := @mnuSaveAsClicked;
|
|
itmFileSaveAll.OnClick := @mnuSaveAllClicked;
|
|
itmFileClose.Enabled := False;
|
|
itmFileClose.OnClick := @mnuCloseClicked;
|
|
itmFileCloseAll.Enabled := False;
|
|
itmFileCloseAll.OnClick := @mnuCloseAllClicked;
|
|
itmFileCleanDirectory.OnClick := @mnuCleanDirectoryClicked;
|
|
itmFileRestart.OnClick := @mnuRestartClicked;
|
|
itmFileQuit.OnClick := @mnuQuitClicked;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupEditMenu;
|
|
begin
|
|
inherited SetupEditMenu;
|
|
mnuEdit.OnClick:=@mnuEditClicked;
|
|
with MainIDEBar do begin
|
|
itmEditUndo.OnClick:=@mnuEditUndoClicked;
|
|
itmEditRedo.OnClick:=@mnuEditRedoClicked;
|
|
itmEditCut.OnClick:=@mnuEditCutClicked;
|
|
itmEditCopy.OnClick:=@mnuEditCopyClicked;
|
|
itmEditPaste.OnClick:=@mnuEditPasteClicked;
|
|
itmEditSelectAll.OnClick:=@mnuEditSelectAllClick;
|
|
itmEditSelectToBrace.OnClick:=@mnuEditSelectToBraceClick;
|
|
itmEditSelectCodeBlock.OnClick:=@mnuEditSelectCodeBlockClick;
|
|
itmEditSelectWord.OnClick:=@mnuEditSelectWordClick;
|
|
itmEditSelectLine.OnClick:=@mnuEditSelectLineClick;
|
|
itmEditSelectParagraph.OnClick:=@mnuEditSelectParagraphClick;
|
|
itmEditIndentBlock.OnClick:=@mnuEditIndentBlockClicked;
|
|
itmEditUnindentBlock.OnClick:=@mnuEditUnindentBlockClicked;
|
|
itmEditUpperCaseBlock.OnClick:=@mnuEditUpperCaseBlockClicked;
|
|
itmEditLowerCaseBlock.OnClick:=@mnuEditLowerCaseBlockClicked;
|
|
itmEditSwapCaseBlock.OnClick:=@mnuEditSwapCaseBlockClicked;
|
|
itmEditSortBlock.OnClick:=@mnuEditSortBlockClicked;
|
|
itmEditTabsToSpacesBlock.OnClick:=@mnuEditTabsToSpacesBlockClicked;
|
|
itmEditSelectionBreakLines.OnClick:=@mnuEditSelectionBreakLinesClicked;
|
|
itmEditInsertCharacter.OnClick:=@mnuEditInsertCharacterClicked;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupSearchMenu;
|
|
begin
|
|
inherited SetupSearchMenu;
|
|
// mnuSearch.OnClick:=@mnuSearchClicked;
|
|
with MainIDEBar do begin
|
|
itmSearchFindIdentifierRefs.OnClick:=@mnuSearchFindIdentifierRefsClicked;
|
|
itmGotoIncludeDirective.OnClick:=@mnuGotoIncludeDirectiveClicked;
|
|
itmSearchProcedureList.OnClick := @mnuSearchProcedureList;
|
|
itmSetFreeBookmark.OnClick := @mnuSetFreeBookmark;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupViewMenu;
|
|
begin
|
|
inherited SetupViewMenu;
|
|
with MainIDEBar do begin
|
|
itmViewInspector.OnClick := @mnuViewInspectorClicked;
|
|
itmViewSourceEditor.OnClick := @mnuViewSourceEditorClicked;
|
|
itmViewCodeExplorer.OnClick := @mnuViewCodeExplorerClick;
|
|
itmViewCodeBrowser.OnClick := @mnuViewCodeBrowserClick;
|
|
itmViewRestrictionBrowser.OnClick := @mnuViewRestrictionBrowserClick;
|
|
itmViewComponents.OnClick := @mnuViewComponentsClick;
|
|
itmViewFPDocEditor.OnClick := @mnuViewFPDocEditorClicked;
|
|
itmViewUnitDependencies.OnClick := @mnuViewUnitDependenciesClicked;
|
|
itmViewToggleFormUnit.OnClick := @mnuToggleFormUnitClicked;
|
|
itmViewMessage.OnClick := @mnuViewMessagesClick;
|
|
itmViewSearchResults.OnClick := @mnuViewSearchResultsClick;
|
|
itmViewAnchorEditor.OnClick := @mnuViewAnchorEditorClicked;
|
|
itmViewTabOrder.OnClick := @mnuViewTabOrderClicked;
|
|
itmViewComponentPalette.OnClick := @mnuViewComponentPaletteClicked;
|
|
itmViewIDESpeedButtons.OnClick := @mnuViewIDESpeedButtonsClicked;
|
|
|
|
itmViewFPCInfo.OnClick:=@mnuViewFPCInfoClicked;
|
|
itmViewIDEInfo.OnClick:=@mnuViewIDEInfoClicked;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupSourceMenu;
|
|
begin
|
|
inherited SetupSourceMenu;
|
|
mnuSource.OnClick:=@mnuSourceClicked;
|
|
with MainIDEBar do begin
|
|
itmSourceCommentBlock.OnClick:=@mnuSourceCommentBlockClicked;
|
|
itmSourceUncommentBlock.OnClick:=@mnuSourceUncommentBlockClicked;
|
|
itmSourceToggleComment.OnClick:=@mnuSourceToggleCommentClicked;
|
|
itmSourceEncloseBlock.OnClick:=@mnuSourceEncloseBlockClicked;
|
|
itmSourceEncloseInIFDEF.OnClick:=@mnuSourceEncloseInIFDEFClicked;
|
|
itmSourceCompleteCode.OnClick:=@mnuSourceCompleteCodeClicked;
|
|
itmSourceUseUnit.OnClick:=@mnuSourceUseUnitClicked;
|
|
// CodeTool Checks
|
|
itmSourceSyntaxCheck.OnClick := @mnuSourceSyntaxCheckClicked;
|
|
itmSourceGuessUnclosedBlock.OnClick := @mnuSourceGuessUnclosedBlockClicked;
|
|
itmSourceGuessMisplacedIFDEF.OnClick := @mnuSourceGuessMisplacedIFDEFClicked;
|
|
// Refactor
|
|
itmRefactorRenameIdentifier.OnClick:=@mnuRefactorRenameIdentifierClicked;
|
|
itmRefactorExtractProc.OnClick:=@mnuRefactorExtractProcClicked;
|
|
itmRefactorInvertAssignment.OnClick:=@mnuRefactorInvertAssignmentClicked;
|
|
// itmRefactorAdvanced
|
|
itmRefactorShowAbstractMethods.OnClick:=@mnuRefactorShowAbstractMethodsClicked;
|
|
itmRefactorShowEmptyMethods.OnClick:=@mnuRefactorShowEmptyMethodsClicked;
|
|
itmRefactorShowUnusedUnits.OnClick:=@mnuRefactorShowUnusedUnitsClicked;
|
|
{$IFDEF EnableFindOverloads}
|
|
itmRefactorFindOverloads.OnClick:=@mnuRefactorFindOverloadsClicked;
|
|
{$ENDIF}
|
|
// itmRefactorTools
|
|
itmRefactorMakeResourceString.OnClick := @mnuRefactorMakeResourceStringClicked;
|
|
// insert CVS keyword
|
|
itmSourceInsertCVSAuthor.OnClick:=@mnuSourceInsertCVSAuthorClick;
|
|
itmSourceInsertCVSDate.OnClick:=@mnuSourceInsertCVSDateClick;
|
|
itmSourceInsertCVSHeader.OnClick:=@mnuSourceInsertCVSHeaderClick;
|
|
itmSourceInsertCVSID.OnClick:=@mnuSourceInsertCVSIDClick;
|
|
itmSourceInsertCVSLog.OnClick:=@mnuSourceInsertCVSLogClick;
|
|
itmSourceInsertCVSName.OnClick:=@mnuSourceInsertCVSNameClick;
|
|
itmSourceInsertCVSRevision.OnClick:=@mnuSourceInsertCVSRevisionClick;
|
|
itmSourceInsertCVSSource.OnClick:=@mnuSourceInsertCVSSourceClick;
|
|
// insert general
|
|
itmSourceInsertGPLNotice.OnClick:=@mnuSourceInsertGPLNoticeClick;
|
|
itmSourceInsertLGPLNotice.OnClick:=@mnuSourceInsertLGPLNoticeClick;
|
|
itmSourceInsertModifiedLGPLNotice.OnClick:=@mnuSourceInsertModifiedLGPLNoticeClick;
|
|
itmSourceInsertUsername.OnClick:=@mnuSourceInsertUsernameClick;
|
|
itmSourceInsertDateTime.OnClick:=@mnuSourceInsertDateTimeClick;
|
|
itmSourceInsertChangeLogEntry.OnClick:=@mnuSourceInsertChangeLogEntryClick;
|
|
itmSourceInsertGUID.OnClick:=@mnuSourceInsertGUID;
|
|
itmSourceInsertFilename.OnClick:=@mnuSourceInsertFilename;
|
|
// Tools
|
|
itmSourceUnitInfo.OnClick := @mnuSourceUnitInfoClicked;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupProjectMenu;
|
|
begin
|
|
inherited SetupProjectMenu;
|
|
mnuProject.OnClick:=@mnuProjectClicked;
|
|
with MainIDEBar do begin
|
|
itmProjectNew.OnClick := @mnuNewProjectClicked;
|
|
itmProjectNewFromFile.OnClick := @mnuNewProjectFromFileClicked;
|
|
itmProjectOpen.OnClick := @mnuOpenProjectClicked;
|
|
SetRecentProjectFilesMenu;
|
|
itmProjectClose.OnClick := @mnuCloseProjectClicked;
|
|
itmProjectSave.OnClick := @mnuSaveProjectClicked;
|
|
itmProjectSaveAs.OnClick := @mnuSaveProjectAsClicked;
|
|
itmProjectPublish.OnClick := @mnuPublishProjectClicked;
|
|
itmProjectInspector.OnClick := @mnuProjectInspectorClicked;
|
|
itmProjectOptions.OnClick := @mnuProjectOptionsClicked;
|
|
itmProjectAddTo.OnClick := @mnuAddToProjectClicked;
|
|
itmProjectRemoveFrom.OnClick := @mnuRemoveFromProjectClicked;
|
|
itmProjectViewUnits.OnClick := @mnuViewUnitsClicked;
|
|
itmProjectViewForms.OnClick := @mnuViewFormsClicked;
|
|
itmProjectViewSource.OnClick := @mnuViewProjectSourceClicked;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupRunMenu;
|
|
begin
|
|
inherited SetupRunMenu;
|
|
with MainIDEBar do begin
|
|
itmRunMenuCompile.OnClick := @mnuCompileProjectClicked;
|
|
itmRunMenuBuild.OnClick := @mnuBuildProjectClicked;
|
|
itmRunMenuQuickCompile.OnClick := @mnuQuickCompileProjectClicked;
|
|
itmRunMenuCleanUpCompiled.OnClick := @mnuCleanUpCompiledProjectClicked;
|
|
itmRunMenuAbortBuild.OnClick := @mnuAbortBuildProjectClicked;
|
|
itmRunMenuRun.OnClick := @mnuRunProjectClicked;
|
|
itmRunMenuPause.OnClick := @mnuPauseProjectClicked;
|
|
itmRunMenuShowExecutionPoint.OnClick := @mnuShowExecutionPointClicked;
|
|
itmRunMenuStepInto.OnClick := @mnuStepIntoProjectClicked;
|
|
itmRunMenuStepOver.OnClick := @mnuStepOverProjectClicked;
|
|
itmRunMenuStepOut.OnClick := @mnuStepOutProjectClicked;
|
|
itmRunMenuRunToCursor.OnClick := @mnuRunToCursorProjectClicked;
|
|
itmRunMenuStop.OnClick := @mnuStopProjectClicked;
|
|
itmRunMenuRunParameters.OnClick := @mnuRunParametersClicked;
|
|
itmRunMenuBuildFile.OnClick := @mnuBuildFileClicked;
|
|
itmRunMenuRunFile.OnClick := @mnuRunFileClicked;
|
|
itmRunMenuConfigBuildFile.OnClick := @mnuConfigBuildFileClicked;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupPackageMenu;
|
|
begin
|
|
inherited SetupPackageMenu;
|
|
mnuPackage.OnClick:=@mnuPackageClicked;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupToolsMenu;
|
|
begin
|
|
inherited SetupToolsMenu;
|
|
with MainIDEBar do begin
|
|
itmEnvGeneralOptions.OnClick := @mnuEnvGeneralOptionsClicked;
|
|
itmToolRescanFPCSrcDir.OnClick := @mnuEnvRescanFPCSrcDirClicked;
|
|
itmEnvCodeTemplates.OnClick := @mnuEnvCodeTemplatesClicked;
|
|
itmEnvCodeToolsDefinesEditor.OnClick := @mnuEnvCodeToolsDefinesEditorClicked;
|
|
|
|
itmToolConfigure.OnClick := @mnuToolConfigureClicked;
|
|
itmToolDiff.OnClick := @mnuToolDiffClicked;
|
|
|
|
itmToolCheckLFM.OnClick := @mnuToolCheckLFMClicked;
|
|
itmToolConvertDFMtoLFM.OnClick := @mnuToolConvertDFMtoLFMClicked;
|
|
itmToolConvertDelphiUnit.OnClick := @mnuToolConvertDelphiUnitClicked;
|
|
itmToolConvertDelphiProject.OnClick := @mnuToolConvertDelphiProjectClicked;
|
|
itmToolConvertDelphiPackage.OnClick := @mnuToolConvertDelphiPackageClicked;
|
|
itmToolConvertEncoding.OnClick := @mnuToolConvertEncodingClicked;
|
|
itmToolManageExamples.OnClick := @mnuToolManageExamplesClicked;
|
|
itmToolBuildLazarus.OnClick := @mnuToolBuildLazarusClicked;
|
|
itmToolConfigureBuildLazarus.OnClick := @mnuToolConfigBuildLazClicked;
|
|
// Set initial caption for Build Lazarus item. Will be changed in BuildLazDialog.
|
|
if Assigned(MiscellaneousOptions) then
|
|
itmToolBuildLazarus.Caption:=
|
|
Format(lisMenuBuildLazarusProf, [MiscellaneousOptions.BuildLazOpts.Name]);
|
|
end;
|
|
UpdateCustomToolsInMenu;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupWindowsMenu;
|
|
begin
|
|
inherited SetupWindowsMenu;
|
|
end;
|
|
|
|
procedure TMainIDE.SetupHelpMenu;
|
|
begin
|
|
inherited SetupHelpMenu;
|
|
end;
|
|
|
|
procedure TMainIDE.LoadMenuShortCuts;
|
|
begin
|
|
inherited LoadMenuShortCuts;
|
|
SourceEditorManager.SetupShortCuts;
|
|
DebugBoss.SetupMainBarShortCuts;
|
|
end;
|
|
|
|
procedure TMainIDE.ConnectMainBarEvents;
|
|
begin
|
|
MainIDEBar.OnClose := @MainIDEFormClose;
|
|
MainIDEBar.OnCloseQuery := @MainIDEFormCloseQuery;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------}
|
|
|
|
procedure TMainIDE.mnuToggleFormUnitClicked(Sender: TObject);
|
|
begin
|
|
DoBringToFrontFormOrUnit;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewAnchorEditorClicked(Sender: TObject);
|
|
begin
|
|
DoViewAnchorEditor(true);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewTabOrderClicked(Sender: TObject);
|
|
begin
|
|
DoViewTabOrderEditor(true);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewComponentPaletteClicked(Sender: TObject);
|
|
begin
|
|
DoToggleViewComponentPalette;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewIDESpeedButtonsClicked(Sender: TObject);
|
|
begin
|
|
DoToggleViewIDESpeedButtons;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewFPCInfoClicked(Sender: TObject);
|
|
begin
|
|
ShowFPCInfo;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewIDEInfoClicked(Sender: TObject);
|
|
begin
|
|
ShowIDEInfo;
|
|
end;
|
|
|
|
procedure TMainIDE.SetDesigning(AComponent: TComponent; Value: Boolean);
|
|
begin
|
|
SetComponentDesignMode(AComponent, Value);
|
|
if Value then
|
|
WidgetSet.SetDesigning(AComponent);
|
|
end;
|
|
|
|
procedure TMainIDE.SetDesignInstance(AComponent: TComponent; Value: Boolean);
|
|
begin
|
|
SetComponentDesignInstanceMode(AComponent, Value);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------}
|
|
procedure TMainIDE.mnuFindDeclarationClicked(Sender: TObject);
|
|
begin
|
|
DoFindDeclarationAtCursor;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuNewUnitClicked(Sender: TObject);
|
|
var
|
|
Category: TNewIDEItemCategory;
|
|
Template: TNewIDEItemTemplate;
|
|
Desc: TProjectFileDescriptor;
|
|
Flags: TNewFlags;
|
|
begin
|
|
Category:=NewIDEItems.FindByName(FileDescGroupName);
|
|
Template:=Category.FindTemplateByName(EnvironmentOptions.NewUnitTemplate);
|
|
if (Template is TNewItemProjectFile) and Template.VisibleInNewDialog then
|
|
Desc:=TNewItemProjectFile(Template).Descriptor
|
|
else
|
|
Desc:=FileDescriptorUnit;
|
|
Flags:=[nfOpenInEditor,nfCreateDefaultSrc];
|
|
if (not Project1.IsVirtual) and EnvironmentOptions.AskForFilenameOnNewFile then
|
|
Flags:=Flags+[nfAskForFilename,nfSave];
|
|
Desc.Owner:=Project1;
|
|
try
|
|
DoNewEditorFile(Desc,'','',Flags);
|
|
finally
|
|
Desc.Owner:=nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuNewFormClicked(Sender: TObject);
|
|
var
|
|
Category: TNewIDEItemCategory;
|
|
Template: TNewIDEItemTemplate;
|
|
Desc: TProjectFileDescriptor;
|
|
Flags: TNewFlags;
|
|
begin
|
|
Category:=NewIDEItems.FindByName(FileDescGroupName);
|
|
Template:=Category.FindTemplateByName(EnvironmentOptions.NewFormTemplate);
|
|
if (Template is TNewItemProjectFile) and Template.VisibleInNewDialog then
|
|
Desc:=TNewItemProjectFile(Template).Descriptor
|
|
else
|
|
Desc:=FileDescriptorForm;
|
|
Flags:=[nfOpenInEditor,nfCreateDefaultSrc];
|
|
if (not Project1.IsVirtual) and EnvironmentOptions.AskForFilenameOnNewFile then
|
|
Flags:=Flags+[nfAskForFilename,nfSave];
|
|
Desc.Owner:=Project1;
|
|
try
|
|
DoNewEditorFile(Desc,'','',Flags);
|
|
finally
|
|
Desc.Owner:=nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuNewOtherClicked(Sender: TObject);
|
|
begin
|
|
DoNewOther;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuOpenClicked(Sender: TObject);
|
|
|
|
procedure UpdateEnvironment;
|
|
begin
|
|
SetRecentFilesMenu;
|
|
SaveEnvironment;
|
|
end;
|
|
|
|
var
|
|
OpenDialog: TOpenDialog;
|
|
AFilename: string;
|
|
I: Integer;
|
|
OpenFlags: TOpenFlags;
|
|
Filter: String;
|
|
AllEditorExt: String;
|
|
AllFilter: String;
|
|
ASrcEdit: TSourceEditor;
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
OpenDialog:=TOpenDialog.Create(nil);
|
|
try
|
|
InputHistories.ApplyFileDialogSettings(OpenDialog);
|
|
OpenDialog.Title:=lisOpenFile;
|
|
OpenDialog.Options:=OpenDialog.Options+[ofAllowMultiSelect];
|
|
|
|
GetCurrentUnit(ASrcEdit,AnUnitInfo);
|
|
if Assigned(AnUnitInfo) then
|
|
OpenDialog.InitialDir:=ExtractFilePath(AnUnitInfo.Filename);
|
|
|
|
// create default filter list
|
|
Filter := lisLazarusUnit + ' (*.pas;*.pp)|*.pas;*.pp'
|
|
+ '|' + lisLazarusProject + ' (*.lpi)|*.lpi'
|
|
+ '|' + lisLazarusForm + ' (*.lfm;*.dfm)|*.lfm;*.dfm'
|
|
+ '|' + lisLazarusPackage + ' (*.lpk)|*.lpk'
|
|
+ '|' + lisLazarusProjectSource + ' (*.lpr)|*.lpr';
|
|
|
|
// append a filter for all file types of the open files in the source editor
|
|
CreateFileDialogFilterForSourceEditorFiles(Filter,AllEditorExt,AllFilter);
|
|
if (AllEditorExt<>'|') then
|
|
Filter:=Filter+ '|' + lisEditorFileTypes + ' (' + AllEditorExt + ')|' +
|
|
AllEditorExt;
|
|
|
|
// append an any file filter *.*
|
|
Filter:=Filter+ '|' + dlgAllFiles + ' (' + GetAllFilesMask + ')|' + GetAllFilesMask;
|
|
|
|
// prepend an all filter
|
|
Filter:= lisLazarusFile + ' ('+AllFilter+')|' + AllFilter + '|' + Filter;
|
|
OpenDialog.Filter := Filter;
|
|
|
|
if OpenDialog.Execute and (OpenDialog.Files.Count>0) then begin
|
|
OpenFlags:=[ofAddToRecent];
|
|
//debugln('TMainIDE.mnuOpenClicked OpenDialog.Files.Count=',dbgs(OpenDialog.Files.Count));
|
|
if OpenDialog.Files.Count>1 then
|
|
Include(OpenFlags,ofRegularFile);
|
|
try
|
|
SourceEditorManager.IncUpdateLock;
|
|
For I := 0 to OpenDialog.Files.Count-1 do
|
|
Begin
|
|
AFilename:=CleanAndExpandFilename(OpenDialog.Files.Strings[i]);
|
|
if i<OpenDialog.Files.Count-1 then
|
|
Include(OpenFlags,ofMultiOpen)
|
|
else
|
|
Exclude(OpenFlags,ofMultiOpen);
|
|
if DoOpenEditorFile(AFilename,-1,-1,OpenFlags)=mrAbort then begin
|
|
break;
|
|
end;
|
|
end;
|
|
finally
|
|
SourceEditorManager.DecUpdateLock;
|
|
end;
|
|
UpdateEnvironment;
|
|
end;
|
|
InputHistories.StoreFileDialogSettings(OpenDialog);
|
|
finally
|
|
OpenDialog.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuOpenRecentClicked(Sender: TObject);
|
|
|
|
procedure UpdateEnvironment;
|
|
begin
|
|
SetRecentFilesMenu;
|
|
SaveEnvironment;
|
|
end;
|
|
|
|
var
|
|
AFilename: string;
|
|
begin
|
|
AFileName:=ExpandFileNameUTF8((Sender as TIDEMenuItem).Caption);
|
|
if DoOpenEditorFile(AFilename,-1,-1,[ofAddToRecent])=mrOk then begin
|
|
UpdateEnvironment;
|
|
end else begin
|
|
// open failed
|
|
if not FileExistsUTF8(AFilename) then begin
|
|
// file does not exist -> delete it from recent file list
|
|
EnvironmentOptions.RemoveFromRecentOpenFiles(AFilename);
|
|
UpdateEnvironment;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuRevertClicked(Sender: TObject);
|
|
begin
|
|
if (SourceEditorManager.ActiveSourceWindowIndex < 0)
|
|
or (SourceEditorManager.ActiveSourceWindow.PageIndex < 0) then exit;
|
|
DoOpenEditorFile('', SourceEditorManager.ActiveSourceWindow.PageIndex,
|
|
SourceEditorManager.ActiveSourceWindowIndex, [ofRevert]);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuOpenFileAtCursorClicked(Sender: TObject);
|
|
begin
|
|
DoOpenFileAtCursor(Sender);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuGotoIncludeDirectiveClicked(Sender: TObject);
|
|
begin
|
|
DoGotoIncludeDirective;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSearchProcedureList(Sender: TObject);
|
|
begin
|
|
ProcedureList.ExecuteProcedureList(Sender);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSetFreeBookmark(Sender: TObject);
|
|
begin
|
|
OnSrcNotebookEditorDoSetBookmark(SourceEditorManager.ActiveEditor, -1, False);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSaveClicked(Sender: TObject);
|
|
begin
|
|
if SourceEditorManager.ActiveEditor = nil then exit;
|
|
DoSaveEditorFile(SourceEditorManager.ActiveEditor, [sfCheckAmbiguousFiles]);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSaveAsClicked(Sender: TObject);
|
|
begin
|
|
if SourceEditorManager.ActiveEditor = nil then exit;
|
|
DoSaveEditorFile(SourceEditorManager.ActiveEditor, [sfSaveAs, sfCheckAmbiguousFiles]);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSaveAllClicked(Sender: TObject);
|
|
begin
|
|
DoSaveAll([sfCheckAmbiguousFiles]);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuCloseClicked(Sender: TObject);
|
|
var
|
|
PageIndex: integer;
|
|
NB: TSourceNotebook;
|
|
begin
|
|
if Sender is TTabSheet then begin
|
|
NB := SourceEditorManager.SourceWindowWithPage(TTabSheet(Sender));
|
|
if NB = nil then exit;
|
|
PageIndex := NB.NotebookPages.IndexOfObject(Sender);
|
|
end else begin
|
|
NB := SourceEditorManager.ActiveSourceWindow;
|
|
if (NB = nil) or (NB.NotebookPages = nil) then exit;
|
|
PageIndex := SourceEditorManager.ActiveSourceWindow.PageIndex;
|
|
end;
|
|
DoCloseEditorFile(NB.FindSourceEditorWithPageIndex(PageIndex), [cfSaveFirst]);
|
|
end;
|
|
|
|
function TMainIDE.CheckEditorNeedsSave(AEditor: TSourceEditorInterface;
|
|
IgnoreSharedEdits: Boolean): Boolean;
|
|
var
|
|
AnEditorInfo: TUnitEditorInfo;
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
Result := False;
|
|
if AEditor = nil then exit;
|
|
AnEditorInfo := Project1.EditorInfoWithEditorComponent(AEditor);
|
|
if AnEditorInfo = nil then exit;
|
|
|
|
AnUnitInfo := AnEditorInfo.UnitInfo;
|
|
if (AnUnitInfo.OpenEditorInfoCount > 1) and IgnoreSharedEdits then
|
|
exit;
|
|
|
|
// save some meta data of the source
|
|
SaveSrcEditorProjectSpecificSettings(AnEditorInfo);
|
|
|
|
Result := (AEditor.Modified) or (AnUnitInfo.Modified);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuCloseAllClicked(Sender: TObject);
|
|
var
|
|
i, NeedSave, Idx: Integer;
|
|
r: TModalResult;
|
|
Ed: TSourceEditor;
|
|
begin
|
|
NeedSave := 0;
|
|
for i := 0 to SourceEditorManager.UniqueSourceEditorCount - 1 do begin
|
|
if CheckEditorNeedsSave(SourceEditorManager.UniqueSourceEditors[i], False) then begin
|
|
inc(NeedSave);
|
|
if NeedSave = 1 then Idx := i;
|
|
end;
|
|
end;
|
|
if NeedSave = 1 then begin
|
|
Ed := TSourceEditor(SourceEditorManager.UniqueSourceEditors[Idx]);
|
|
r := QuestionDlg(lisSourceModified,
|
|
Format(lisSourceOfPageHasChangedSave, ['"', Ed.PageName, '"']),
|
|
mtConfirmation,
|
|
[mrYes, lisMenuSave, mrNo, lisDiscardChanges, mrAbort], 0);
|
|
case r of
|
|
mrYes: DoSaveEditorFile(Ed, [sfCheckAmbiguousFiles]);
|
|
mrNo: ; // don't save
|
|
mrAbort: exit;
|
|
end;
|
|
|
|
end
|
|
else if NeedSave > 1 then begin
|
|
for i := 0 to SourceEditorManager.UniqueSourceEditorCount - 1 do begin
|
|
if CheckEditorNeedsSave(SourceEditorManager.UniqueSourceEditors[i], False) then begin
|
|
dec(NeedSave);
|
|
Ed := TSourceEditor(SourceEditorManager.UniqueSourceEditors[i]);
|
|
r := QuestionDlg(lisSourceModified,
|
|
Format(lisSourceOfPageHasChangedSaveExtended, ['"', Ed.PageName, '"', NeedSave]),
|
|
mtConfirmation,
|
|
[mrYes, lisMenuSave, mrAll, lisMenuSaveAll,
|
|
mrNo, lisDiscardChanges, mrIgnore, lisDiscardChangesAll,
|
|
mrAbort], 0);
|
|
case r of
|
|
mrYes: DoSaveEditorFile(Ed, [sfCheckAmbiguousFiles]);
|
|
mrNo: ; // don't save
|
|
mrAll: begin
|
|
DoSaveAll([]);
|
|
break
|
|
end;
|
|
mrIgnore: break; // don't save anymore
|
|
mrAbort: exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
SourceEditorManager.IncUpdateLock;
|
|
try
|
|
while (SourceEditorManager.SourceEditorCount > 0) and
|
|
(DoCloseEditorFile(SourceEditorManager.SourceEditors[0],
|
|
[]) = mrOk)
|
|
do ;
|
|
finally
|
|
SourceEditorManager.DecUpdateLock;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuCleanDirectoryClicked(Sender: TObject);
|
|
begin
|
|
ShowCleanDirectoryDialog(Project1.ProjectDirectory,GlobalMacroList);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookFileNew(Sender: TObject);
|
|
begin
|
|
mnuNewFormClicked(Sender);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookFileClose(Sender: TObject;
|
|
InvertedClose: boolean);
|
|
var
|
|
PageIndex: LongInt;
|
|
i, NeedSave, Idx: Integer;
|
|
ActiveSrcNoteBook: TSourceNotebook;
|
|
Ed: TSourceEditor;
|
|
r: TModalResult;
|
|
begin
|
|
if InvertedClose then begin
|
|
// close all source editors except the clicked
|
|
if Sender is TTabSheet then begin
|
|
ActiveSrcNoteBook := SourceEditorManager.SourceWindowWithPage(TTabSheet(Sender));
|
|
if ActiveSrcNoteBook = nil then exit;
|
|
PageIndex := ActiveSrcNoteBook.NotebookPages.IndexOfObject(Sender);
|
|
end else begin
|
|
ActiveSrcNoteBook := SourceEditorManager.ActiveSourceWindow;
|
|
if ActiveSrcNoteBook = nil then exit;
|
|
PageIndex := ActiveSrcNoteBook.PageIndex;
|
|
end;
|
|
|
|
NeedSave := 0;
|
|
for i := 0 to ActiveSrcNoteBook.EditorCount - 1 do begin
|
|
if CheckEditorNeedsSave(ActiveSrcNoteBook.Editors[i], True) then begin
|
|
inc(NeedSave);
|
|
if NeedSave = 1 then Idx := i;
|
|
end;
|
|
end;
|
|
if NeedSave = 1 then begin
|
|
Ed := ActiveSrcNoteBook.Editors[Idx];
|
|
r := QuestionDlg(lisSourceModified,
|
|
Format(lisSourceOfPageHasChangedSave, ['"', Ed.PageName, '"']),
|
|
mtConfirmation,
|
|
[mrYes, lisMenuSave, mrNo, lisDiscardChanges, mrAbort], 0);
|
|
case r of
|
|
mrYes: DoSaveEditorFile(Ed, [sfCheckAmbiguousFiles]);
|
|
mrNo: ; // don't save
|
|
mrAbort: exit;
|
|
end;
|
|
|
|
end
|
|
else if NeedSave > 1 then begin
|
|
for i := 0 to ActiveSrcNoteBook.EditorCount - 1 do begin
|
|
if CheckEditorNeedsSave(ActiveSrcNoteBook.Editors[i], True) then begin
|
|
dec(NeedSave);
|
|
Ed := ActiveSrcNoteBook.Editors[i];
|
|
r := QuestionDlg(lisSourceModified,
|
|
Format(lisSourceOfPageHasChangedSaveExtended, ['"', Ed.PageName, '"', NeedSave]),
|
|
mtConfirmation,
|
|
[mrYes, lisMenuSave, mrAll, lisMenuSaveAll,
|
|
mrNo, lisDiscardChanges, mrIgnore, lisDiscardChangesAll,
|
|
mrAbort], 0);
|
|
case r of
|
|
mrYes: DoSaveEditorFile(Ed, [sfCheckAmbiguousFiles]);
|
|
mrNo: ; // don't save
|
|
mrAll: begin
|
|
DoSaveAll([]);
|
|
break
|
|
end;
|
|
mrIgnore: break; // don't save anymore
|
|
mrAbort: exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
SourceEditorManager.IncUpdateLock;
|
|
try
|
|
repeat
|
|
i:=ActiveSrcNoteBook.PageCount-1;
|
|
if i=PageIndex then dec(i);
|
|
if i<0 then break;
|
|
if DoCloseEditorFile(ActiveSrcNoteBook.FindSourceEditorWithPageIndex(i),[])<>mrOk then exit;
|
|
if i<PageIndex then PageIndex:=i;
|
|
until false;
|
|
finally
|
|
SourceEditorManager.DecUpdateLock;
|
|
end
|
|
end else
|
|
// close only the clicked source editor
|
|
mnuCloseClicked(Sender);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookFileOpen(Sender: TObject);
|
|
begin
|
|
mnuOpenClicked(Sender);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookFileOpenAtCursor(Sender: TObject);
|
|
begin
|
|
mnuOpenFileAtCursorClicked(Sender);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookFileSave(Sender: TObject);
|
|
begin
|
|
mnuSaveClicked(Sender);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookFileSaveAs(Sender: TObject);
|
|
begin
|
|
mnuSaveAsClicked(Sender);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookFindDeclaration(Sender: TObject);
|
|
begin
|
|
mnuFindDeclarationClicked(Sender);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookInitIdentCompletion(Sender: TObject;
|
|
JumpToError: boolean; out Handled, Abort: boolean);
|
|
begin
|
|
Handled:=true;
|
|
Abort:=not DoInitIdentCompletion(JumpToError);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookShowCodeContext(
|
|
JumpToError: boolean; out Abort: boolean);
|
|
begin
|
|
Abort:=not DoShowCodeContext(JumpToError);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookSaveAll(Sender: TObject);
|
|
begin
|
|
mnuSaveAllClicked(Sender);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookToggleFormUnit(Sender: TObject);
|
|
begin
|
|
mnuToggleFormUnitClicked(Sender);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookToggleObjectInsp(Sender: TObject);
|
|
begin
|
|
mnuViewInspectorClicked(Sender);
|
|
end;
|
|
|
|
procedure TMainIDE.OnProcessIDECommand(Sender: TObject;
|
|
Command: word; var Handled: boolean);
|
|
var
|
|
ASrcEdit: TSourceEditor;
|
|
AnUnitInfo: TUnitInfo;
|
|
IDECmd: TIDECommand;
|
|
begin
|
|
//debugln('TMainIDE.OnProcessIDECommand ',dbgs(Command));
|
|
|
|
Handled:=true;
|
|
|
|
case Command of
|
|
|
|
ecContextHelp:
|
|
if Sender=MessagesView then
|
|
HelpBoss.ShowHelpForMessage(-1)
|
|
else if Sender is TObjectInspectorDlg then
|
|
HelpBoss.ShowHelpForObjectInspector(Sender);
|
|
|
|
ecSave:
|
|
if (Sender is TDesigner) then begin
|
|
GetDesignerUnit(TDesigner(Sender),ASrcEdit,AnUnitInfo);
|
|
if (AnUnitInfo<>nil) and (AnUnitInfo.OpenEditorInfoCount > 0) then
|
|
DoSaveEditorFile(ASrcEdit, [sfCheckAmbiguousFiles]);
|
|
end else if (Sender is TObjectInspectorDlg) then begin
|
|
GetObjectInspectorUnit(ASrcEdit,AnUnitInfo);
|
|
if (AnUnitInfo<>nil) and (AnUnitInfo.OpenEditorInfoCount > 0) then
|
|
DoSaveEditorFile(ASrcEdit, [sfCheckAmbiguousFiles]);
|
|
end else if Sender is TSourceNotebook then
|
|
mnuSaveClicked(Self);
|
|
|
|
ecOpen:
|
|
mnuOpenClicked(Self);
|
|
|
|
ecSaveAll:
|
|
DoSaveAll([sfCheckAmbiguousFiles]);
|
|
|
|
ecQuit:
|
|
mnuQuitClicked(Self);
|
|
|
|
ecCompile:
|
|
begin
|
|
GetCurrentUnit(ASrcEdit,AnUnitInfo);
|
|
if Assigned(AnUnitInfo) and AnUnitInfo.BuildFileIfActive then
|
|
DoBuildFile(false)
|
|
else
|
|
DoBuildProject(crCompile, []);
|
|
end;
|
|
|
|
ecBuild: DoBuildProject(crBuild, [pbfCleanCompile, pbfCompileDependenciesClean]);
|
|
ecCleanUpCompiled: mnuCleanUpCompiledProjectClicked(nil);
|
|
ecQuickCompile: DoQuickCompile;
|
|
ecAbortBuild: DoAbortBuild;
|
|
|
|
ecRun:
|
|
begin
|
|
GetCurrentUnit(ASrcEdit,AnUnitInfo);
|
|
if (AnUnitInfo<>nil)
|
|
and AnUnitInfo.RunFileIfActive then
|
|
DoRunFile
|
|
else
|
|
DoRunProject;
|
|
end;
|
|
|
|
ecBuildFile:
|
|
DoBuildFile(false);
|
|
|
|
ecRunFile:
|
|
DoRunFile;
|
|
|
|
ecJumpToPrevError:
|
|
DoJumpToNextError(true);
|
|
|
|
ecJumpToNextError:
|
|
DoJumpToNextError(false);
|
|
|
|
ecFindInFiles:
|
|
DoFindInFiles;
|
|
|
|
ecFindProcedureDefinition,
|
|
ecFindProcedureMethod:
|
|
DoJumpToOtherProcedureSection;
|
|
|
|
ecFindDeclaration:
|
|
DoFindDeclarationAtCursor;
|
|
|
|
ecFindIdentifierRefs:
|
|
DoFindRenameIdentifier(false);
|
|
|
|
ecRenameIdentifier:
|
|
DoFindRenameIdentifier(true);
|
|
|
|
ecShowAbstractMethods:
|
|
DoShowAbstractMethods;
|
|
|
|
ecRemoveEmptyMethods:
|
|
DoRemoveEmptyMethods;
|
|
|
|
ecRemoveUnusedUnits:
|
|
DoRemoveUnusedUnits;
|
|
|
|
ecUseUnit:
|
|
DoUseUnit;
|
|
|
|
ecFindOverloads:
|
|
DoFindOverloads;
|
|
|
|
ecFindBlockOtherEnd:
|
|
DoGoToPascalBlockOtherEnd;
|
|
|
|
ecFindBlockStart:
|
|
DoGoToPascalBlockStart;
|
|
|
|
ecGotoIncludeDirective:
|
|
DoGotoIncludeDirective;
|
|
|
|
ecCompleteCode:
|
|
DoCompleteCodeAtCursor;
|
|
|
|
ecExtractProc:
|
|
DoExtractProcFromSelection;
|
|
|
|
ecToggleMessages:
|
|
// user used shortcut/menu item to show the window, so focusing is ok.
|
|
DoShowMessagesView;
|
|
|
|
ecToggleCodeExpl:
|
|
DoShowCodeExplorer(true);
|
|
|
|
ecToggleCodeBrowser:
|
|
DoShowCodeBrowser(true);
|
|
|
|
ecToggleRestrictionBrowser:
|
|
DoShowRestrictionBrowser(true);
|
|
|
|
ecViewComponents:
|
|
DoShowComponentList(true);
|
|
|
|
ecToggleFPDocEditor:
|
|
DoShowFPDocEditor(true,true);
|
|
|
|
ecViewProjectUnits:
|
|
DoViewUnitsAndForms(false);
|
|
|
|
ecViewProjectForms:
|
|
DoViewUnitsAndForms(true);
|
|
|
|
ecProjectInspector:
|
|
DoShowProjectInspector(true);
|
|
|
|
ecConfigCustomComps:
|
|
PkgBoss.ShowConfigureCustomComponents;
|
|
|
|
ecExtToolFirst..ecExtToolLast:
|
|
DoRunExternalTool(Command-ecExtToolFirst,false);
|
|
|
|
ecSyntaxCheck:
|
|
DoCheckSyntax;
|
|
|
|
ecGuessUnclosedBlock:
|
|
DoJumpToGuessedUnclosedBlock(true);
|
|
|
|
ecGuessMisplacedIFDEF:
|
|
DoJumpToGuessedMisplacedIFDEF(true);
|
|
|
|
ecMakeResourceString:
|
|
DoMakeResourceString;
|
|
|
|
ecDiff:
|
|
DoDiff;
|
|
|
|
ecConvertDFM2LFM:
|
|
DoConvertDFMtoLFM;
|
|
|
|
ecManageExamples:
|
|
mnuToolManageExamplesClicked(Self);
|
|
|
|
ecBuildLazarus:
|
|
mnuToolBuildLazarusClicked(Self);
|
|
|
|
ecBuildAdvancedLazarus:
|
|
mnuToolBuildAdvancedLazarusClicked(Self);
|
|
|
|
ecConfigBuildLazarus:
|
|
mnuToolConfigBuildLazClicked(Self);
|
|
|
|
ecToggleFormUnit:
|
|
mnuToggleFormUnitClicked(Self);
|
|
|
|
ecToggleObjectInsp:
|
|
mnuViewInspectorClicked(Self);
|
|
|
|
ecToggleSearchResults:
|
|
mnuViewSearchResultsClick(Self);
|
|
|
|
ecAboutLazarus:
|
|
MainIDEBar.itmHelpAboutLazarus.OnClick(Self);
|
|
|
|
ecToggleBreakPoint:
|
|
SourceEditorManager.ActiveSourceWindow.ToggleBreakpointClicked(Self);
|
|
|
|
ecRemoveBreakPoint:
|
|
SourceEditorManager.ActiveSourceWindow.DeleteBreakpointClicked(Self);
|
|
|
|
ecProcedureList:
|
|
mnuSearchProcedureList(self);
|
|
|
|
ecInsertGUID:
|
|
mnuSourceInsertGUID(self);
|
|
|
|
ecInsertFilename:
|
|
mnuSourceInsertFilename(self);
|
|
|
|
else
|
|
Handled:=false;
|
|
// let the bosses handle it
|
|
DebugBoss.ProcessCommand(Command,Handled);
|
|
if Handled then exit;
|
|
PkgBoss.ProcessCommand(Command,Handled);
|
|
if Handled then exit;
|
|
// custom commands
|
|
IDECmd:=IDECommandList.FindIDECommand(Command);
|
|
//DebugLn('TMainIDE.OnProcessIDECommand Command=',dbgs(Command),' ',dbgs(IDECmd));
|
|
if (IDECmd<>nil) then begin
|
|
Handled:=IDECmd.Execute(IDECmd);
|
|
end;
|
|
end;
|
|
|
|
//DebugLn('TMainIDE.OnProcessIDECommand Handled=',dbgs(Handled),' Command=',dbgs(Command));
|
|
end;
|
|
|
|
function TMainIDE.OnExecuteIDECommand(Sender: TObject; Command: word): boolean;
|
|
begin
|
|
Result:=false;
|
|
OnProcessIDECommand(Sender,Command,Result);
|
|
end;
|
|
|
|
function TMainIDE.OnSelectDirectory(const Title, InitialDir: string): string;
|
|
var
|
|
Dialog: TSelectDirectoryDialog;
|
|
DummyResult: Boolean;
|
|
begin
|
|
Result:='';
|
|
Dialog:=TSelectDirectoryDialog.Create(nil);
|
|
try
|
|
InputHistories.ApplyFileDialogSettings(Dialog);
|
|
Dialog.Title:=Title;
|
|
Dialog.Options:=Dialog.Options+[ofFileMustExist];
|
|
if InitialDir<>'' then
|
|
Dialog.InitialDir:=InitialDir;
|
|
DummyResult:=Dialog.Execute;
|
|
InputHistories.StoreFileDialogSettings(Dialog);
|
|
if DummyResult and DirPathExists(Dialog.Filename) then begin
|
|
Result:=Dialog.Filename;
|
|
end;
|
|
finally
|
|
Dialog.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnInitIDEFileDialog(AFileDialog: TFileDialog);
|
|
begin
|
|
InputHistories.ApplyFileDialogSettings(AFileDialog);
|
|
end;
|
|
|
|
procedure TMainIDE.OnStoreIDEFileDialog(AFileDialog: TFileDialog);
|
|
begin
|
|
InputHistories.StoreFileDialogSettings(AFileDialog);
|
|
end;
|
|
|
|
function TMainIDE.OnIDEMessageDialog(const aCaption, aMsg: string;
|
|
DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; const HelpKeyword: string
|
|
): Integer;
|
|
begin
|
|
Result:=MessageDlg(aCaption,aMsg,DlgType,Buttons,HelpKeyword);
|
|
end;
|
|
|
|
function TMainIDE.OnIDEQuestionDialog(const aCaption, aMsg: string;
|
|
DlgType: TMsgDlgType; Buttons: array of const; const HelpKeyword: string
|
|
): Integer;
|
|
begin
|
|
Result:=QuestionDlg(aCaption,aMsg,DlgType,Buttons,HelpKeyword);
|
|
end;
|
|
|
|
procedure TMainIDE.OnExecuteIDEShortCut(Sender: TObject; var Key: word;
|
|
Shift: TShiftState;
|
|
IDEWindowClass: TCustomFormClass);
|
|
var
|
|
Command: Word;
|
|
Handled: Boolean;
|
|
begin
|
|
if Key=VK_UNKNOWN then exit;
|
|
Command := EditorOpts.KeyMap.TranslateKey(Key,Shift,IDEWindowClass);
|
|
if (Command = ecNone) then exit;
|
|
Handled := false;
|
|
OnProcessIDECommand(Sender, Command, Handled);
|
|
if Handled then
|
|
Key := VK_UNKNOWN;
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNoteBookClickLink(Sender: TObject;
|
|
Button: TMouseButton; Shift: TShiftstate; X, Y: Integer);
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
begin
|
|
GetCurrentUnit(ActiveSrcEdit,ActiveUnitInfo);
|
|
if ActiveSrcEdit=nil then exit;
|
|
DoFindDeclarationAtCaret(
|
|
ActiveSrcEdit.EditorComponent.PixelsToLogicalPos(Point(X,Y)));
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNoteBookShowUnitInfo(Sender: TObject);
|
|
begin
|
|
DoViewUnitInfo;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------}
|
|
|
|
procedure TMainIDE.OpenFilePopupMenuPopup(Sender: TObject);
|
|
var
|
|
CurIndex: integer;
|
|
OpenMenuItem: TPopupMenu;
|
|
|
|
procedure AddFile(const Filename: string);
|
|
var
|
|
AMenuItem: TMenuItem;
|
|
begin
|
|
if MainIDEBar.OpenFilePopupMenu.Items.Count > CurIndex then
|
|
AMenuItem := MainIDEBar.OpenFilePopupMenu.Items[CurIndex]
|
|
else
|
|
begin
|
|
AMenuItem := TMenuItem.Create(OwningComponent);
|
|
AMenuItem.Name := MainIDEBar.OpenFilePopupMenu.Name + 'Recent' + IntToStr(CurIndex);
|
|
AMenuItem.OnClick := @mnuOpenFilePopupClick;
|
|
MainIDEBar.OpenFilePopupMenu.Items.Add(AMenuItem);
|
|
end;
|
|
AMenuItem.Caption := Filename;
|
|
inc(CurIndex);
|
|
end;
|
|
|
|
procedure AddFiles(List: TStringList; MaxCount: integer);
|
|
var
|
|
i: integer;
|
|
begin
|
|
i := 0;
|
|
while (i < List.Count) and (i < MaxCount) do
|
|
begin
|
|
AddFile(List[i]);
|
|
inc(i);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
// fill the PopupMenu:
|
|
CurIndex := 0;
|
|
// first add 8 recent projects
|
|
AddFiles(EnvironmentOptions.RecentProjectFiles, 8);
|
|
// add a separator
|
|
AddFile('-');
|
|
// add 12 recent files
|
|
AddFiles(EnvironmentOptions.RecentOpenFiles, 12);
|
|
OpenMenuItem := MainIDEBar.OpenFilePopupMenu;
|
|
// remove unused menuitems
|
|
while OpenMenuItem.Items.Count > CurIndex do
|
|
OpenMenuItem.Items[OpenMenuItem.Items.Count - 1].Free;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuOpenFilePopupClick(Sender: TObject);
|
|
var
|
|
TheMenuItem: TMenuItem;
|
|
Index, SeparatorIndex: integer;
|
|
AFilename: string;
|
|
begin
|
|
TheMenuItem:=(Sender as TMenuItem);
|
|
if TheMenuItem.Caption='-' then exit;
|
|
Index:=TheMenuItem.MenuIndex;
|
|
SeparatorIndex:=0;
|
|
while SeparatorIndex<MainIDEBar.OpenFilePopupMenu.Items.Count do begin
|
|
if MainIDEBar.OpenFilePopupMenu.Items[SeparatorIndex].Caption='-' then
|
|
break;
|
|
inc(SeparatorIndex);
|
|
end;
|
|
if Index=SeparatorIndex then exit;
|
|
if Index<SeparatorIndex then begin
|
|
// open recent project
|
|
AFilename:=EnvironmentOptions.RecentProjectFiles[Index];
|
|
DoOpenProjectFile(AFileName,[ofAddToRecent]);
|
|
end else begin
|
|
// open recent file
|
|
dec(Index, SeparatorIndex+1);
|
|
if DoOpenEditorFile(EnvironmentOptions.RecentOpenFiles[Index],-1,-1,
|
|
[ofAddToRecent])=mrOk then
|
|
begin
|
|
SetRecentFilesMenu;
|
|
SaveEnvironment;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.SetBuildModePopupMenuPopup(Sender: TObject);
|
|
var
|
|
aMenu: TPopupMenu;
|
|
CurIndex: Integer;
|
|
i: Integer;
|
|
|
|
procedure AddMode(CurMode: TProjectBuildMode);
|
|
var
|
|
AMenuItem: TMenuItem;
|
|
begin
|
|
if aMenu.Items.Count > CurIndex then
|
|
AMenuItem := aMenu.Items[CurIndex]
|
|
else
|
|
begin
|
|
AMenuItem := TMenuItem.Create(OwningComponent);
|
|
AMenuItem.Name := aMenu.Name + 'Mode' + IntToStr(CurIndex);
|
|
AMenuItem.OnClick := @mnuSetBuildModeClick;
|
|
aMenu.Items.Add(AMenuItem);
|
|
end;
|
|
AMenuItem.Caption := CurMode.GetCaption;
|
|
AMenuItem.Checked:=Project1.ActiveBuildMode=CurMode;
|
|
AMenuItem.ShowAlwaysCheckable:=true;
|
|
inc(CurIndex);
|
|
end;
|
|
|
|
begin
|
|
// fill the PopupMenu:
|
|
CurIndex := 0;
|
|
aMenu := MainIDEBar.SetBuildModePopupMenu;
|
|
if Project1<>nil then
|
|
for i:=0 to Project1.BuildModes.Count-1 do
|
|
AddMode(Project1.BuildModes[i]);
|
|
// remove unused menuitems
|
|
while aMenu.Items.Count > CurIndex do
|
|
aMenu.Items[aMenu.Items.Count - 1].Free;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuChgBuildModeClicked(Sender: TObject);
|
|
begin
|
|
DoOpenIDEOptions(TBuildModesEditorFrame, '', [TProjectCompilerOptions], []);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSetBuildModeClick(Sender: TObject);
|
|
var
|
|
TheMenuItem: TMenuItem;
|
|
Index: LongInt;
|
|
NewMode: TProjectBuildMode;
|
|
begin
|
|
TheMenuItem:=(Sender as TMenuItem);
|
|
if TheMenuItem.Caption='-' then exit;
|
|
Index:=TheMenuItem.MenuIndex;
|
|
if (Index<0) or (Index>=Project1.BuildModes.Count) then exit;
|
|
NewMode:=Project1.BuildModes[Index];
|
|
if NewMode=Project1.ActiveBuildMode then exit;
|
|
if not (ToolStatus in [itNone,itDebugger]) then begin
|
|
IDEMessageDialog('Error','You can not change the build mode while compiling.',
|
|
mtError,[mbOk]);
|
|
exit;
|
|
end;
|
|
|
|
Project1.ActiveBuildMode:=NewMode;
|
|
MainBuildBoss.SetBuildTargetProject1(false);
|
|
end;
|
|
|
|
function TMainIDE.CreateDesignerForComponent(AnUnitInfo: TUnitInfo;
|
|
AComponent: TComponent): TCustomForm;
|
|
var
|
|
DesignerForm: TCustomForm;
|
|
begin
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TMainIDE.CreateDesignerForComponent] A ',AComponent.Name,':',AComponent.ClassName);
|
|
{$ENDIF}
|
|
// create designer form
|
|
if (AComponent is TCustomForm) then
|
|
DesignerForm := TCustomForm(AComponent)
|
|
else
|
|
DesignerForm := FormEditor1.CreateNonFormForm(AComponent);
|
|
Result:=DesignerForm;
|
|
// set component and designer form into design mode (csDesigning)
|
|
SetDesigning(AComponent, True);
|
|
if AComponent <> DesignerForm then
|
|
SetDesigning(DesignerForm, True);
|
|
SetDesignInstance(AComponent, True);
|
|
if AComponent is TControl then
|
|
TControl(AComponent).ControlStyle:=
|
|
TControl(AComponent).ControlStyle-[csNoDesignVisible];
|
|
// create designer
|
|
DesignerForm.Designer := TDesigner.Create(DesignerForm, TheControlSelection);
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TMainIDE.CreateDesignerForComponent] B');
|
|
{$ENDIF}
|
|
with TDesigner(DesignerForm.Designer) do begin
|
|
TheFormEditor := FormEditor1;
|
|
OnActivated:=@OnDesignerActivated;
|
|
OnCloseQuery:=@OnDesignerCloseQuery;
|
|
OnPersistentDeleted:=@OnDesignerPersistentDeleted;
|
|
OnGetNonVisualCompIcon:=
|
|
@TComponentPalette(IDEComponentPalette).OnGetNonVisualCompIcon;
|
|
OnGetSelectedComponentClass:=@OnDesignerGetSelectedComponentClass;
|
|
OnModified:=@OnDesignerModified;
|
|
OnPasteComponent:=@OnDesignerPasteComponent;
|
|
OnProcessCommand:=@OnProcessIDECommand;
|
|
OnPropertiesChanged:=@OnDesignerPropertiesChanged;
|
|
OnRenameComponent:=@OnDesignerRenameComponent;
|
|
OnSetDesigning:=@OnDesignerSetDesigning;
|
|
OnShowOptions:=@OnDesignerShowOptions;
|
|
OnComponentAdded:=@OnDesignerComponentAdded;
|
|
OnViewLFM:=@OnDesignerViewLFM;
|
|
OnSaveAsXML:=@OnDesignerSaveAsXML;
|
|
OnShowObjectInspector:=@OnDesignerShowObjectInspector;
|
|
OnShowAnchorEditor:=@OnDesignerShowAnchorEditor;
|
|
OnShowTabOrderEditor:=@OnDesignerShowTabOrderEditor;
|
|
ShowEditorHints:=EnvironmentOptions.ShowEditorHints;
|
|
ShowComponentCaptions := EnvironmentOptions.ShowComponentCaptions;
|
|
end;
|
|
if AnUnitInfo<>nil then
|
|
AnUnitInfo.LoadedDesigner:=true;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
procedure TMainIDE.InvalidateAllDesignerForms
|
|
Params: none
|
|
Result: none
|
|
|
|
Calls 'Invalidate' in all designer forms.
|
|
-------------------------------------------------------------------------------}
|
|
procedure TMainIDE.InvalidateAllDesignerForms;
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
CurDesignerForm: TCustomForm;
|
|
begin
|
|
AnUnitInfo:=Project1.FirstUnitWithComponent;
|
|
while AnUnitInfo<>nil do begin
|
|
if AnUnitInfo.Component<>nil then begin
|
|
CurDesignerForm:=FormEditor1.GetDesignerForm(AnUnitInfo.Component);
|
|
if CurDesignerForm<>nil then
|
|
CurDesignerForm.Invalidate;
|
|
end;
|
|
AnUnitInfo:=AnUnitInfo.NextUnitWithComponent;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.UpdateIDEComponentPalette;
|
|
begin
|
|
IDEComponentPalette.HideControls:=(FLastFormActivated<>nil)
|
|
and (not (TDesigner(FLastFormActivated.Designer).LookupRoot is TControl));
|
|
IDEComponentPalette.UpdateVisible;
|
|
TComponentPalette(IDEComponentPalette).OnClassSelected := @ComponentPaletteClassSelected;
|
|
SetupHints;
|
|
end;
|
|
|
|
procedure TMainIDE.ShowDesignerForm(AForm: TCustomForm);
|
|
begin
|
|
// do not call 'AForm.Show', because it will set Visible to true
|
|
AForm.BringToFront;
|
|
LCLIntf.ShowWindow(AForm.Handle,SW_SHOWNORMAL);
|
|
end;
|
|
|
|
procedure TMainIDE.DoViewAnchorEditor(Show: boolean);
|
|
begin
|
|
if AnchorDesigner=nil then
|
|
AnchorDesigner:=TAnchorDesigner.Create(OwningComponent);
|
|
if Show then
|
|
IDEWindowCreators.ShowForm(AnchorDesigner,true);
|
|
end;
|
|
|
|
procedure TMainIDE.DoViewTabOrderEditor(Show: boolean);
|
|
begin
|
|
if TabOrderDialog=nil then
|
|
TabOrderDialog:=TTabOrderDialog.Create(OwningComponent);
|
|
if Show then
|
|
IDEWindowCreators.ShowForm(TabOrderDialog,true);
|
|
end;
|
|
|
|
procedure TMainIDE.DoToggleViewComponentPalette;
|
|
var
|
|
ComponentPaletteVisible: boolean;
|
|
begin
|
|
ComponentPaletteVisible:=not MainIDEBar.ComponentPageControl.Visible;
|
|
MainIDEBar.itmViewComponentPalette.Checked:=ComponentPaletteVisible;
|
|
MainIDEBar.ComponentPageControl.Visible:=ComponentPaletteVisible;
|
|
EnvironmentOptions.ComponentPaletteVisible:=ComponentPaletteVisible;
|
|
end;
|
|
|
|
procedure TMainIDE.DoToggleViewIDESpeedButtons;
|
|
var
|
|
SpeedButtonsVisible: boolean;
|
|
begin
|
|
SpeedButtonsVisible:=not MainIDEBar.pnlSpeedButtons.Visible;
|
|
MainIDEBar.itmViewIDESpeedButtons.Checked:=SpeedButtonsVisible;
|
|
MainIDEBar.pnlSpeedButtons.Visible:=SpeedButtonsVisible;
|
|
EnvironmentOptions.IDESpeedButtonsVisible:=MainIDEBar.pnlSpeedButtons.Visible;
|
|
end;
|
|
|
|
procedure TMainIDE.SetToolStatus(const AValue: TIDEToolStatus);
|
|
begin
|
|
inherited SetToolStatus(AValue);
|
|
if DebugBoss <> nil then
|
|
DebugBoss.UpdateButtonsAndMenuItems;
|
|
if FWaitForClose and (ToolStatus = itNone) then
|
|
begin
|
|
FWaitForClose := False;
|
|
MainIDEBar.Close;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoResetToolStatus(AFlags: TResetToolFlags): boolean;
|
|
begin
|
|
Result := False;
|
|
case ToolStatus of
|
|
itDebugger:
|
|
begin
|
|
if (rfInteractive in AFlags)
|
|
and (QuestionDlg(lisStopDebugging,
|
|
lisStopTheDebugging, mtConfirmation,
|
|
[mrYes, lisMenuStop, mrCancel, lisContinue], 0) <> mrYes)
|
|
then exit;
|
|
if (DebugBoss.DoStopProject = mrOK) and (ToolStatus = itDebugger) and (rfCloseOnDone in AFlags) then
|
|
FWaitForClose := True;
|
|
end;
|
|
end;
|
|
Result := ToolStatus = itNone;
|
|
end;
|
|
|
|
procedure TMainIDE.Notification(AComponent: TComponent; Operation: TOperation);
|
|
begin
|
|
inherited Notification(AComponent, Operation);
|
|
end;
|
|
|
|
|
|
{------------------------------------------------------------------------------}
|
|
|
|
procedure TMainIDE.mnuRestartClicked(Sender: TObject);
|
|
begin
|
|
DoRestart;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuQuitClicked(Sender: TObject);
|
|
begin
|
|
QuitIDE;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditClicked(Sender: TObject);
|
|
var
|
|
ASrcEdit: TSourceEditor;
|
|
AnUnitInfo: TUnitInfo;
|
|
Editable: Boolean;
|
|
SelAvail: Boolean;
|
|
SelEditable: Boolean;
|
|
SrcEditorActive: Boolean;
|
|
begin
|
|
GetCurrentUnit(ASrcEdit,AnUnitInfo);
|
|
Editable:=(ASrcEdit<>nil) and (not ASrcEdit.ReadOnly);
|
|
SelAvail:=(ASrcEdit<>nil) and (ASrcEdit.SelectionAvailable);
|
|
SelEditable:=Editable and SelAvail;
|
|
SrcEditorActive:=FDisplayState=dsSource;
|
|
with MainIDEBar do begin
|
|
itmEditUndo.Enabled:=Editable and SrcEditorActive;
|
|
itmEditRedo.Enabled:=Editable and SrcEditorActive;
|
|
//itmEditClipboard: TIDEMenuSection;
|
|
itmEditCut.Enabled:=SelEditable;
|
|
itmEditCopy.Enabled:=SelAvail;
|
|
itmEditPaste.Enabled:=Editable;
|
|
//itmEditSelect: TIDEMenuSection; [...]
|
|
//itmEditBlockActions: TIDEMenuSection;
|
|
itmEditIndentBlock.Enabled:=Editable;
|
|
itmEditUnindentBlock.Enabled:=Editable;
|
|
itmEditUpperCaseBlock.Enabled:=SelEditable;
|
|
itmEditLowerCaseBlock.Enabled:=SelEditable;
|
|
itmEditSwapCaseBlock.Enabled:=SelEditable;
|
|
itmEditSortBlock.Enabled:=SelEditable;
|
|
itmEditTabsToSpacesBlock.Enabled:=SelEditable;
|
|
itmEditSelectionBreakLines.Enabled:=SelEditable;
|
|
itmEditInsertCharacter.Enabled:=Editable;
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------}
|
|
|
|
procedure TMainIDE.mnuSourceClicked(Sender: TObject);
|
|
var
|
|
ASrcEdit: TSourceEditor;
|
|
AnUnitInfo: TUnitInfo;
|
|
Editable, SelEditable, SelAvail, IdentFound, StringFound: Boolean;
|
|
StartCode, EndCode: TCodeBuffer;
|
|
StartPos, EndPos: TPoint;
|
|
NewX, NewY, NewTopLine: integer;
|
|
CursorXY: TPoint;
|
|
begin
|
|
Editable:=False;
|
|
SelAvail:=False;
|
|
IdentFound:=False;
|
|
StringFound:=False;
|
|
if BeginCodeTool(ASrcEdit,AnUnitInfo,[]) then begin
|
|
Assert(Assigned(ASrcEdit));
|
|
Editable:=not ASrcEdit.ReadOnly;
|
|
SelAvail:=ASrcEdit.SelectionAvailable;
|
|
|
|
// Try to find main identifier declaration to enable rename feature.
|
|
CursorXY:=ASrcEdit.EditorComponent.LogicalCaretXY;
|
|
IdentFound:=CodeToolBoss.FindMainDeclaration(AnUnitInfo.Source,
|
|
CursorXY.X,CursorXY.Y,StartCode,NewX,NewY,NewTopLine);
|
|
|
|
// Calculate start and end of string expr to enable ResourceString feature.
|
|
if ASrcEdit.EditorComponent.SelAvail then
|
|
CursorXY:=ASrcEdit.EditorComponent.BlockBegin;
|
|
if CodeToolBoss.GetStringConstBounds(AnUnitInfo.Source,CursorXY.X,CursorXY.Y,
|
|
StartCode,StartPos.X,StartPos.Y,
|
|
EndCode,EndPos.X,EndPos.Y,true) then
|
|
StringFound:=(StartCode<>EndCode) or (CompareCaret(StartPos,EndPos)<>0);
|
|
end;
|
|
SelEditable:=Editable and SelAvail;
|
|
with MainIDEBar do begin
|
|
//itmSourceBlockActions
|
|
itmSourceCommentBlock.Enabled:=SelEditable;
|
|
itmSourceUncommentBlock.Enabled:=SelEditable;
|
|
itmSourceEncloseBlock.Enabled:=SelEditable;
|
|
itmSourceEncloseInIFDEF.Enabled:=SelEditable;
|
|
itmSourceCompleteCode.Enabled:=Editable;
|
|
itmSourceUseUnit.Enabled:=Editable;
|
|
//itmSourceInsertions
|
|
//itmSourceInsertCVSKeyWord
|
|
itmSourceInsertCVSAuthor.Enabled:=Editable;
|
|
itmSourceInsertCVSDate.Enabled:=Editable;
|
|
itmSourceInsertCVSHeader.Enabled:=Editable;
|
|
itmSourceInsertCVSID.Enabled:=Editable;
|
|
itmSourceInsertCVSLog.Enabled:=Editable;
|
|
itmSourceInsertCVSName.Enabled:=Editable;
|
|
itmSourceInsertCVSRevision.Enabled:=Editable;
|
|
itmSourceInsertCVSSource.Enabled:=Editable;
|
|
//itmSourceInsertGeneral
|
|
itmSourceInsertGPLNotice.Enabled:=Editable;
|
|
itmSourceInsertLGPLNotice.Enabled:=Editable;
|
|
itmSourceInsertModifiedLGPLNotice.Enabled:=Editable;
|
|
itmSourceInsertUsername.Enabled:=Editable;
|
|
itmSourceInsertDateTime.Enabled:=Editable;
|
|
itmSourceInsertChangeLogEntry.Enabled:=Editable;
|
|
//itmSourceRefactor
|
|
//itmRefactorCodeTools
|
|
itmRefactorRenameIdentifier.Enabled:=Editable and IdentFound;
|
|
itmRefactorExtractProc.Enabled:=Editable and SelAvail;
|
|
itmRefactorInvertAssignment.Enabled:=Editable and SelAvail;
|
|
//itmRefactorAdvanced
|
|
itmRefactorMakeResourceString.Enabled:=Editable and StringFound;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuProjectClicked(Sender: TObject);
|
|
var
|
|
ASrcEdit: TSourceEditor;
|
|
AUnitInfo: TUnitInfo;
|
|
NotPartOfProj: Boolean;
|
|
begin
|
|
GetCurrentUnit(ASrcEdit,AUnitInfo);
|
|
NotPartOfProj:=Assigned(AUnitInfo) and not AUnitInfo.IsPartOfProject;
|
|
MainIDEBar.itmProjectAddTo.Enabled:=NotPartOfProj;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuPackageClicked(Sender: TObject);
|
|
var
|
|
ASrcEdit: TSourceEditor;
|
|
AUnitInfo: TUnitInfo;
|
|
PkgFile: TPkgFile;
|
|
OpenPkgCurF, AddCurF: Boolean;
|
|
begin
|
|
OpenPkgCurF:=False;
|
|
AddCurF:=False;
|
|
GetCurrentUnit(ASrcEdit,AUnitInfo);
|
|
if Assigned(ASrcEdit) then begin
|
|
PkgFile:=PackageGraph.FindFileInAllPackages(AUnitInfo.Filename,true,
|
|
not AUnitInfo.IsPartOfProject);
|
|
OpenPkgCurF:=Assigned(PkgFile);
|
|
AddCurF:=(not AUnitInfo.IsVirtual) and FileExistsUTF8(AUnitInfo.Filename)
|
|
and not AUnitInfo.IsPartOfProject;
|
|
end;
|
|
MainIDEBar.itmPkgOpenPackageOfCurUnit.Enabled:=OpenPkgCurF;
|
|
MainIDEBar.itmPkgAddCurFileToPkg.Enabled:=AddCurF;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------}
|
|
procedure TMainIDE.mnuViewInspectorClicked(Sender: TObject);
|
|
begin
|
|
DoBringToFrontFormOrInspector(true);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewSourceEditorClicked(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
SourceEditorManager.ActiveOrNewSourceWindow;
|
|
for i := 0 to SourceEditorManager.SourceWindowCount - 1 do
|
|
SourceEditorManager.SourceWindows[i].Show;
|
|
SourceEditorManager.ShowActiveWindowOnTop(False);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------}
|
|
|
|
procedure TMainIDE.mnuViewUnitsClicked(Sender: TObject);
|
|
begin
|
|
DoViewUnitsAndForms(false);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewFormsClicked(Sender: TObject);
|
|
Begin
|
|
DoViewUnitsAndForms(true);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewUnitDependenciesClicked(Sender: TObject);
|
|
begin
|
|
DoViewUnitDependencies(true);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceUnitInfoClicked(Sender: TObject);
|
|
begin
|
|
DoViewUnitInfo;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewCodeExplorerClick(Sender: TObject);
|
|
begin
|
|
DoShowCodeExplorer(true);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewCodeBrowserClick(Sender: TObject);
|
|
begin
|
|
DoShowCodeBrowser(true);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewComponentsClick(Sender: TObject);
|
|
begin
|
|
DoShowComponentList(true);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewRestrictionBrowserClick(Sender: TObject);
|
|
begin
|
|
DoShowRestrictionBrowser(true);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewMessagesClick(Sender: TObject);
|
|
begin
|
|
// it was already visible, but user does not see it, try to move in view
|
|
DoShowMessagesView;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewSearchResultsClick(Sender: TObject);
|
|
Begin
|
|
ShowSearchResultView(true);
|
|
End;
|
|
|
|
procedure TMainIDE.mnuNewProjectClicked(Sender: TObject);
|
|
var
|
|
NewProjectDesc: TProjectDescriptor;
|
|
Begin
|
|
NewProjectDesc:=nil;
|
|
if ChooseNewProject(NewProjectDesc)<>mrOk then exit;
|
|
//debugln('TMainIDE.mnuNewProjectClicked ',dbgsName(NewProjectDesc));
|
|
DoNewProject(NewProjectDesc);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuNewProjectFromFileClicked(Sender: TObject);
|
|
var
|
|
OpenDialog:TOpenDialog;
|
|
AFilename: string;
|
|
PreReadBuf: TCodeBuffer;
|
|
Filter: String;
|
|
Begin
|
|
OpenDialog:=TOpenDialog.Create(nil);
|
|
try
|
|
InputHistories.ApplyFileDialogSettings(OpenDialog);
|
|
OpenDialog.Title:=lisChooseProgramSourcePpPasLpr;
|
|
OpenDialog.Options:=OpenDialog.Options+[ofPathMustExist,ofFileMustExist];
|
|
Filter := lisLazarusUnit + ' (*.pas;*.pp;*.p)|*.pas;*.pp;*.p'
|
|
+ '|' + lisLazarusProjectSource + ' (*.lpr)|*.lpr';
|
|
Filter:=Filter+ '|' + dlgAllFiles + ' (' + GetAllFilesMask + ')|' + GetAllFilesMask;
|
|
OpenDialog.Filter := Filter;
|
|
if OpenDialog.Execute then begin
|
|
AFilename:=ExpandFileNameUTF8(OpenDialog.Filename);
|
|
if not FilenameIsPascalSource(AFilename) then begin
|
|
IDEMessageDialog(lisPkgMangInvalidFileExtension,
|
|
lisProgramSourceMustHaveAPascalExtensionLikePasPpOrLp,
|
|
mtError,[mbOk],'');
|
|
exit;
|
|
end;
|
|
if mrOk<>LoadCodeBuffer(PreReadBuf,AFileName,
|
|
[lbfCheckIfText,lbfUpdateFromDisk,lbfRevert],false)
|
|
then
|
|
exit;
|
|
if DoCreateProjectForProgram(PreReadBuf)=mrOk then begin
|
|
exit;
|
|
end;
|
|
end;
|
|
finally
|
|
InputHistories.StoreFileDialogSettings(OpenDialog);
|
|
OpenDialog.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuOpenProjectClicked(Sender: TObject);
|
|
var
|
|
OpenDialog:TOpenDialog;
|
|
AFileName: string;
|
|
LoadFlags: TLoadBufferFlags;
|
|
PreReadBuf: TCodeBuffer;
|
|
SourceType: String;
|
|
LPIFilename: String;
|
|
begin
|
|
if (Sender is TIDEMenuItem)
|
|
and (TIDEMenuItem(Sender).Section=itmProjectRecentOpen) then begin
|
|
AFileName:=ExpandFileNameUTF8(TIDEMenuItem(Sender).Caption);
|
|
if DoOpenProjectFile(AFilename,[ofAddToRecent])=mrOk then begin
|
|
AddRecentProjectFileToEnvironment(AFilename);
|
|
end else begin
|
|
// open failed
|
|
if not FileExistsUTF8(AFilename) then begin
|
|
EnvironmentOptions.RemoveFromRecentProjectFiles(AFilename);
|
|
end else
|
|
AddRecentProjectFileToEnvironment(AFilename);
|
|
end;
|
|
end
|
|
else begin
|
|
OpenDialog:=TOpenDialog.Create(nil);
|
|
try
|
|
InputHistories.ApplyFileDialogSettings(OpenDialog);
|
|
OpenDialog.Title:=lisOpenProjectFile+' (*.lpi)';
|
|
OpenDialog.Filter := lisLazarusProjectInfoFile+' (*.lpi)|*.lpi|'
|
|
+lisAllFiles+'|'+GetAllFilesMask;
|
|
if OpenDialog.Execute then begin
|
|
AFilename:=ExpandFileNameUTF8(OpenDialog.Filename);
|
|
if FileUtil.CompareFileExt(AFilename,'.lpi')<>0 then begin
|
|
// not a lpi file
|
|
// check if it is a program source
|
|
|
|
// load the source
|
|
LoadFlags := [lbfCheckIfText,lbfUpdateFromDisk,lbfRevert];
|
|
if LoadCodeBuffer(PreReadBuf,AFileName,LoadFlags,true)<>mrOk then exit;
|
|
|
|
// check if unit is a program
|
|
SourceType:=CodeToolBoss.GetSourceType(PreReadBuf,false);
|
|
if (SysUtils.CompareText(SourceType,'PROGRAM')=0)
|
|
or (SysUtils.CompareText(SourceType,'LIBRARY')=0)
|
|
then begin
|
|
// source is a program
|
|
// either this is a lazarus project
|
|
// or it is not yet a lazarus project ;)
|
|
LPIFilename:=ChangeFileExt(AFilename,'.lpi');
|
|
if FileExistsUTF8(LPIFilename) then begin
|
|
if QuestionDlg(lisProjectInfoFileDetected,
|
|
Format(lisTheFileSeemsToBeTheProgramFileOfAnExistingLazarusP, [
|
|
AFilename]), mtConfirmation,
|
|
[mrOk, lisOpenProject2, mrCancel], 0)
|
|
<>mrOk
|
|
then
|
|
exit;
|
|
AFilename:=LPIFilename;
|
|
end else begin
|
|
if QuestionDlg(lisFileHasNoProject,
|
|
Format(lisTheFileIsNotALazarusProjectCreateANewProjectForThi, [
|
|
'"', AFilename, '"', #13, '"'+lowercase(SourceType)+'"']),
|
|
mtConfirmation, [mrYes, lisCreateProject, mrCancel], 0)<>mrYes
|
|
then
|
|
exit;
|
|
DoCreateProjectForProgram(PreReadBuf);
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
DoOpenProjectFile(AFilename,[ofAddToRecent]);
|
|
end;
|
|
InputHistories.StoreFileDialogSettings(OpenDialog);
|
|
finally
|
|
OpenDialog.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuCloseProjectClicked(Sender: TObject);
|
|
var
|
|
DlgResult: TModalResult;
|
|
ARecentProject: String;
|
|
begin
|
|
// stop debugging/compiling/...
|
|
if not DoResetToolStatus([rfInteractive]) then exit;
|
|
|
|
// check foreign windows
|
|
if not CloseQueryIDEWindows then exit;
|
|
|
|
// check project
|
|
if SomethingOfProjectIsModified then begin
|
|
DlgResult:=QuestionDlg(lisProjectChanged,
|
|
Format(lisSaveChangesToProject, [Project1.GetTitleOrName]), mtConfirmation,
|
|
[mrYes, lisMenuSave, mrNoToAll, lisDiscardChanges,
|
|
mrAbort, lisDoNotCloseTheProject],
|
|
0);
|
|
case DlgResult of
|
|
mrYes:
|
|
if not (DoSaveProject([]) in [mrOk,mrIgnore]) then exit;
|
|
mrCancel, mrAbort:
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
// close
|
|
DoCloseProject;
|
|
|
|
// ask what to do next
|
|
while (Project1 = nil) do
|
|
begin
|
|
case ShowProjectWizardDlg(ARecentProject) of
|
|
tpws_new:
|
|
mnuNewProjectClicked(Sender);
|
|
tpws_open:
|
|
mnuOpenProjectClicked(Sender);
|
|
tpws_openRecent:
|
|
begin
|
|
ARecentProject := ExpandFileNameUTF8(ARecentProject);
|
|
if DoOpenProjectFile(ARecentProject, [ofAddToRecent]) <> mrOk then
|
|
begin
|
|
// open failed
|
|
if not FileExistsUTF8(ARecentProject) then
|
|
EnvironmentOptions.RemoveFromRecentProjectFiles(ARecentProject)
|
|
else
|
|
AddRecentProjectFileToEnvironment(ARecentProject);
|
|
end;
|
|
end;
|
|
tpws_examples:
|
|
mnuToolManageExamplesClicked(Sender);
|
|
tpws_convert:
|
|
mnuToolConvertDelphiProjectClicked(Sender);
|
|
tpws_closeIDE:
|
|
if QuitIDE then exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSaveProjectClicked(Sender: TObject);
|
|
Begin
|
|
DoSaveProject([]);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSaveProjectAsClicked(Sender: TObject);
|
|
begin
|
|
DoSaveProject([sfSaveAs]);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuPublishProjectClicked(Sender: TObject);
|
|
begin
|
|
DoPublishProject([],true);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuProjectInspectorClicked(Sender: TObject);
|
|
begin
|
|
DoShowProjectInspector(true);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuAddToProjectClicked(Sender: TObject);
|
|
begin
|
|
DoAddActiveUnitToProject;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuRemoveFromProjectClicked(Sender: TObject);
|
|
begin
|
|
DoRemoveFromProjectDialog;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewProjectSourceClicked(Sender: TObject);
|
|
begin
|
|
DoOpenMainUnit(-1,-1,[]);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuProjectOptionsClicked(Sender: TObject);
|
|
begin
|
|
DoOpenIDEOptions(nil, Format(dlgProjectOptionsFor, [Project1.GetTitleOrName]),
|
|
[TProject, TProjectCompilerOptions], []);
|
|
end;
|
|
|
|
function TMainIDE.UpdateProjectPOFile(AProject: TProject): TModalResult;
|
|
var
|
|
Files: TStringList;
|
|
POFilename: String;
|
|
AnUnitInfo: TUnitInfo;
|
|
CurFilename: String;
|
|
POFileAge: LongInt;
|
|
POFileAgeValid: Boolean;
|
|
POOutDir: String;
|
|
LRTFilename: String;
|
|
UnitOutputDir: String;
|
|
RSTFilename: String;
|
|
begin
|
|
Result:=mrCancel;
|
|
if (not AProject.EnableI18N) or AProject.IsVirtual then exit(mrOk);
|
|
|
|
POFilename := MainBuildBoss.GetProjectTargetFilename(AProject);
|
|
if POFilename='' then begin
|
|
DebugLn(['TMainIDE.UpdateProjectPOFile unable to get project target filename']);
|
|
exit;
|
|
end;
|
|
POFilename:=ChangeFileExt(POFilename, '.po');
|
|
|
|
if AProject.POOutputDirectory <> '' then begin
|
|
POOutDir:=AProject.GetPOOutDirectory;
|
|
if POOutDir<>'' then begin
|
|
if not DirPathExistsCached(POOutDir) then begin
|
|
Result:=ForceDirectoryInteractive(POOutDir,[]);
|
|
if Result in [mrCancel,mrAbort] then exit;
|
|
if Result<>mrOk then
|
|
POOutDir:=''; // e.g. ignore if failed to create dir
|
|
end;
|
|
if POOutDir<>'' then
|
|
POFilename:=AppendPathDelim(POOutDir)+ExtractFileName(POFilename);
|
|
end;
|
|
end;
|
|
|
|
POFileAgeValid:=false;
|
|
if FileExistsCached(POFilename) then begin
|
|
POFileAge:=FileAgeCached(POFilename);
|
|
POFileAgeValid:=true;
|
|
end;
|
|
|
|
//DebugLn(['TMainIDE.UpdateProjectPOFile Updating POFilename="',POFilename,'"']);
|
|
|
|
Files := TStringList.Create;
|
|
try
|
|
AnUnitInfo:=AProject.FirstPartOfProject;
|
|
while AnUnitInfo<>nil do begin
|
|
CurFilename:=AnUnitInfo.Filename;
|
|
if (not AnUnitInfo.IsVirtual) and FilenameIsPascalSource(CurFilename) then
|
|
begin
|
|
// check .lrt file
|
|
LRTFilename:=ChangeFileExt(CurFilename,'.lrt');
|
|
if FileExistsCached(LRTFilename)
|
|
and ((not POFileAgeValid) or (FileAgeCached(LRTFilename)>POFileAge)) then
|
|
Files.Add(LRTFilename);
|
|
// check .rst file
|
|
RSTFilename:=ChangeFileExt(CurFilename,'.rst');
|
|
|
|
// the compiler puts the .rst in the unit output directory if -FU is given
|
|
if AProject.CompilerOptions.UnitOutputDirectory<>'' then
|
|
begin
|
|
UnitOutputDir:=AProject.GetOutputDirectory;
|
|
if UnitOutputDir<>'' then
|
|
RSTFilename:=TrimFilename(AppendPathDelim(UnitOutputDir)+ExtractFilename(RSTFilename));
|
|
end;
|
|
//DebugLn(['TMainIDE.UpdateProjectPOFile Looking for .rst file ="',RSTFilename,'"']);
|
|
|
|
if FileExistsCached(RSTFilename)
|
|
and ((not POFileAgeValid) or (FileAgeCached(RSTFilename)>POFileAge)) then
|
|
Files.Add(RSTFilename);
|
|
end;
|
|
AnUnitInfo:=AnUnitInfo.NextPartOfProject;
|
|
end;
|
|
|
|
try
|
|
UpdatePoFile(Files, POFilename);
|
|
Result := mrOk;
|
|
except
|
|
on E:EPOFileError do begin
|
|
IDEMessageDialog(lisCCOErrorCaption, Format(lisErrorLoadingFrom,
|
|
[ 'Update PO file '+E.POFileName, #13, E.ResFileName, #13#13,
|
|
E.Message]), mtError, [mbOk]);
|
|
end;
|
|
end;
|
|
|
|
finally
|
|
Files.Destroy;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuCompileProjectClicked(Sender: TObject);
|
|
var
|
|
ASrcEdit: TSourceEditor;
|
|
AnUnitInfo: TUnitInfo;
|
|
Begin
|
|
GetCurrentUnit(ASrcEdit,AnUnitInfo);
|
|
if (AnUnitInfo<>nil)
|
|
and AnUnitInfo.BuildFileIfActive then
|
|
DoBuildFile(false)
|
|
else
|
|
DoBuildProject(crCompile,[]);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuBuildProjectClicked(Sender: TObject);
|
|
Begin
|
|
DoBuildProject(crBuild,[pbfCleanCompile,pbfCompileDependenciesClean]);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuQuickCompileProjectClicked(Sender: TObject);
|
|
begin
|
|
DoQuickCompile;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuCleanUpCompiledProjectClicked(Sender: TObject);
|
|
begin
|
|
if Project1.MainUnitInfo=nil then begin
|
|
// this project has no source to compile
|
|
IDEMessageDialog(lisCanNotCompileProject,
|
|
lisTheProjectHasNoMainSourceFile, mtError, [mbCancel], '');
|
|
exit;
|
|
end;
|
|
|
|
if PrepareForCompile<>mrOk then exit;
|
|
|
|
if ShowBuildProjectDialog(Project1)<>mrOk then exit;
|
|
|
|
DoBuildProject(crBuild,[]);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuAbortBuildProjectClicked(Sender: TObject);
|
|
Begin
|
|
DoAbortBuild;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuRunProjectClicked(Sender: TObject);
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
GetCurrentUnit(SrcEdit,AnUnitInfo);
|
|
if (AnUnitInfo<>nil) and AnUnitInfo.RunFileIfActive then
|
|
DoRunFile
|
|
else
|
|
DoRunProject;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuPauseProjectClicked(Sender: TObject);
|
|
begin
|
|
DebugBoss.DoPauseProject;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuShowExecutionPointClicked(Sender: TObject);
|
|
begin
|
|
DebugBoss.DoShowExecutionPoint;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuStepIntoProjectClicked(Sender: TObject);
|
|
begin
|
|
DebugBoss.DoStepIntoProject;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuStepOverProjectClicked(Sender: TObject);
|
|
begin
|
|
DebugBoss.DoStepOverProject;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuStepIntoInstrProjectClicked(Sender: TObject);
|
|
begin
|
|
DebugBoss.DoStepIntoInstrProject;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuStepOverInstrProjectClicked(Sender: TObject);
|
|
begin
|
|
DebugBoss.DoStepOverInstrProject;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuStepOutProjectClicked(Sender: TObject);
|
|
begin
|
|
DebugBoss.DoStepOutProject;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuRunToCursorProjectClicked(Sender: TObject);
|
|
begin
|
|
DebugBoss.DoRunToCursor;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuStopProjectClicked(Sender: TObject);
|
|
begin
|
|
DebugBoss.DoStopProject;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuBuildFileClicked(Sender: TObject);
|
|
begin
|
|
DoBuildFile(false);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuRunFileClicked(Sender: TObject);
|
|
begin
|
|
DoRunFile;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuConfigBuildFileClicked(Sender: TObject);
|
|
begin
|
|
DoConfigBuildFile;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuRunParametersClicked(Sender: TObject);
|
|
begin
|
|
if ShowRunParamsOptsDlg(Project1.RunParameterOptions)=mrOK then
|
|
Project1.Modified:=true;
|
|
end;
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
procedure TMainIDE.mnuToolConfigureClicked(Sender: TObject);
|
|
begin
|
|
if ShowExtToolDialog(ExternalTools,GlobalMacroList)=mrOk then
|
|
begin
|
|
// save to environment options
|
|
SaveDesktopSettings(EnvironmentOptions);
|
|
EnvironmentOptions.Save(false);
|
|
// save shortcuts to editor options
|
|
ExternalTools.SaveShortCuts(EditorOpts.KeyMap);
|
|
EditorOpts.Save;
|
|
UpdateHighlighters(True);
|
|
SourceEditorManager.ReloadEditorOptions;
|
|
UpdateCustomToolsInMenu;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceSyntaxCheckClicked(Sender: TObject);
|
|
begin
|
|
DoCheckSyntax;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceGuessUnclosedBlockClicked(Sender: TObject);
|
|
begin
|
|
DoJumpToGuessedUnclosedBlock(true);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceGuessMisplacedIFDEFClicked(Sender: TObject);
|
|
begin
|
|
DoJumpToGuessedMisplacedIFDEF(true);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuRefactorMakeResourceStringClicked(Sender: TObject);
|
|
begin
|
|
DoMakeResourceString;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuToolDiffClicked(Sender: TObject);
|
|
begin
|
|
DoDiff;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuViewFPDocEditorClicked(Sender: TObject);
|
|
begin
|
|
DoShowFPDocEditor(true,true);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuToolConvertDFMtoLFMClicked(Sender: TObject);
|
|
begin
|
|
DoConvertDFMtoLFM;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuToolCheckLFMClicked(Sender: TObject);
|
|
begin
|
|
DoCheckLFMInEditor(false);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuToolConvertDelphiUnitClicked(Sender: TObject);
|
|
|
|
procedure UpdateEnvironment;
|
|
begin
|
|
SetRecentFilesMenu;
|
|
SaveEnvironment;
|
|
end;
|
|
|
|
var
|
|
OpenDialog: TOpenDialog;
|
|
AFilename: string;
|
|
i: Integer;
|
|
MultiOpen: Boolean;
|
|
begin
|
|
OpenDialog:=TOpenDialog.Create(nil);
|
|
try
|
|
InputHistories.ApplyFileDialogSettings(OpenDialog);
|
|
OpenDialog.Title:=lisChooseDelphiUnit;
|
|
OpenDialog.Filter:=lisDelphiUnit+' (*.pas)|*.pas|'+
|
|
dlgAllFiles+' ('+GetAllFilesMask+')|' + GetAllFilesMask;
|
|
OpenDialog.Options:=OpenDialog.Options+[ofAllowMultiSelect];
|
|
if InputHistories.LastConvertDelphiUnit<>'' then begin
|
|
OpenDialog.InitialDir:=
|
|
ExtractFilePath(InputHistories.LastConvertDelphiUnit);
|
|
OpenDialog.Filename:=
|
|
ExtractFileName(InputHistories.LastConvertDelphiUnit);
|
|
end;
|
|
if OpenDialog.Execute and (OpenDialog.Files.Count>0) then begin
|
|
MultiOpen:=OpenDialog.Files.Count>1;
|
|
for i := 0 to OpenDialog.Files.Count-1 do begin
|
|
AFilename:=CleanAndExpandFilename(OpenDialog.Files.Strings[i]);
|
|
if FileExistsUTF8(AFilename)
|
|
and (DoConvertDelphiUnit(AFilename,MultiOpen)=mrAbort) then
|
|
break;
|
|
end;
|
|
UpdateEnvironment;
|
|
end;
|
|
InputHistories.StoreFileDialogSettings(OpenDialog);
|
|
finally
|
|
OpenDialog.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuToolConvertDelphiProjectClicked(Sender: TObject);
|
|
|
|
procedure UpdateEnvironment;
|
|
begin
|
|
SetRecentFilesMenu;
|
|
SaveEnvironment;
|
|
end;
|
|
|
|
var
|
|
OpenDialog: TOpenDialog;
|
|
AFilename: string;
|
|
begin
|
|
OpenDialog:=TOpenDialog.Create(nil);
|
|
try
|
|
InputHistories.ApplyFileDialogSettings(OpenDialog);
|
|
OpenDialog.Title:=lisChooseDelphiProject;
|
|
OpenDialog.Filter:=lisDelphiProject+' (*.dpr)|*.dpr|'+
|
|
lisLazarusProject+' (*.lpr)|*.lpr|'+
|
|
dlgAllFiles+' ('+GetAllFilesMask+')|' + GetAllFilesMask;
|
|
if InputHistories.LastConvertDelphiProject<>'' then begin
|
|
OpenDialog.InitialDir:=
|
|
ExtractFilePath(InputHistories.LastConvertDelphiProject);
|
|
OpenDialog.Filename:=
|
|
ExtractFileName(InputHistories.LastConvertDelphiProject);
|
|
end;
|
|
if OpenDialog.Execute then begin
|
|
AFilename:=CleanAndExpandFilename(OpenDialog.Filename);
|
|
if FileExistsUTF8(AFilename) then
|
|
DoConvertDelphiProject(AFilename);
|
|
UpdateEnvironment;
|
|
end;
|
|
InputHistories.StoreFileDialogSettings(OpenDialog);
|
|
finally
|
|
OpenDialog.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuToolConvertDelphiPackageClicked(Sender: TObject);
|
|
|
|
procedure UpdateEnvironment;
|
|
begin
|
|
SetRecentFilesMenu;
|
|
SaveEnvironment;
|
|
end;
|
|
|
|
var
|
|
OpenDialog: TOpenDialog;
|
|
AFilename: string;
|
|
begin
|
|
OpenDialog:=TOpenDialog.Create(nil);
|
|
try
|
|
InputHistories.ApplyFileDialogSettings(OpenDialog);
|
|
OpenDialog.Title:=lisChooseDelphiPackage;
|
|
OpenDialog.Filter:=lisDelphiPackage+' (*.dpk)|*.dpk|'+
|
|
dlgAllFiles+' ('+GetAllFilesMask+')|' + GetAllFilesMask;
|
|
if InputHistories.LastConvertDelphiPackage<>'' then begin
|
|
OpenDialog.InitialDir:=
|
|
ExtractFilePath(InputHistories.LastConvertDelphiPackage);
|
|
OpenDialog.Filename:=
|
|
ExtractFileName(InputHistories.LastConvertDelphiPackage);
|
|
end;
|
|
if OpenDialog.Execute then begin
|
|
AFilename:=CleanAndExpandFilename(OpenDialog.Filename);
|
|
//debugln('TMainIDE.mnuToolConvertDelphiProjectClicked A ',AFilename);
|
|
if FileExistsUTF8(AFilename) then
|
|
DoConvertDelphiPackage(AFilename);
|
|
UpdateEnvironment;
|
|
end;
|
|
InputHistories.StoreFileDialogSettings(OpenDialog);
|
|
finally
|
|
OpenDialog.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuToolConvertEncodingClicked(Sender: TObject);
|
|
begin
|
|
ShowConvertEncodingDlg;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuToolManageExamplesClicked(Sender: TObject);
|
|
begin
|
|
DoManageExamples();
|
|
end;
|
|
|
|
procedure TMainIDE.mnuToolBuildLazarusClicked(Sender: TObject);
|
|
begin
|
|
with MiscellaneousOptions do
|
|
if BuildLazProfiles.ConfirmBuild then
|
|
if MessageDlg(Format(lisConfirmLazarusRebuild, [BuildLazProfiles.Current.Name]),
|
|
mtConfirmation, mbYesNo, 0)<>mrYes then
|
|
exit;
|
|
DoBuildLazarus([]);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuToolBuildAdvancedLazarusClicked(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
FoundProfToBuild: Boolean;
|
|
s: String;
|
|
begin
|
|
with MiscellaneousOptions do begin
|
|
FoundProfToBuild:=False;
|
|
s:=sLineBreak+sLineBreak;
|
|
for i:=0 to BuildLazProfiles.Selected.Count-1 do
|
|
if BuildLazProfiles.IndexByName(BuildLazProfiles.Selected[i])<>-1 then begin
|
|
s:=s+BuildLazProfiles.Selected[i]+sLineBreak;
|
|
FoundProfToBuild:=True;
|
|
end;
|
|
if not FoundProfToBuild then begin
|
|
ShowMessage(lisNoBuildProfilesSelected);
|
|
exit;
|
|
end;
|
|
if BuildLazProfiles.ConfirmBuild then
|
|
if MessageDlg(Format(lisConfirmBuildAllProfiles, [s+sLineBreak]),
|
|
mtConfirmation, mbYesNo, 0)<>mrYes then
|
|
exit;
|
|
DoBuildAdvancedLazarus(BuildLazProfiles.Selected);
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuToolConfigBuildLazClicked(Sender: TObject);
|
|
var
|
|
CmdLineDefines: TDefineTemplate;
|
|
LazSrcTemplate: TDefineTemplate;
|
|
LazSrcDirTemplate: TDefineTemplate;
|
|
DlgResult: TModalResult;
|
|
begin
|
|
DlgResult:=ShowConfigureBuildLazarusDlg(MiscellaneousOptions.BuildLazProfiles);
|
|
if DlgResult in [mrOk,mrYes,mrAll] then begin
|
|
MiscellaneousOptions.Save;
|
|
if DlgResult=mrAll then
|
|
DoBuildAdvancedLazarus(MiscellaneousOptions.BuildLazProfiles.Selected)
|
|
else if DlgResult=mrYes then begin
|
|
LazSrcTemplate:=
|
|
CodeToolBoss.DefineTree.FindDefineTemplateByName(StdDefTemplLazarusSources,true);
|
|
if Assigned(LazSrcTemplate) then begin
|
|
LazSrcDirTemplate:=LazSrcTemplate.FindChildByName(StdDefTemplLazarusSrcDir);
|
|
if Assigned(LazSrcDirTemplate) then begin
|
|
CmdLineDefines:=CodeToolBoss.DefinePool.CreateFPCCommandLineDefines(
|
|
StdDefTemplLazarusBuildOpts,
|
|
MiscellaneousOptions.BuildLazProfiles.Current.ExtraOptions,
|
|
true,CodeToolsOpts);
|
|
CodeToolBoss.DefineTree.ReplaceChild(LazSrcDirTemplate,CmdLineDefines,
|
|
StdDefTemplLazarusBuildOpts);
|
|
end;
|
|
end;
|
|
DoBuildLazarus([]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
procedure TMainIDE.mnuCustomExtToolClick(Sender: TObject);
|
|
|
|
Handler for clicking on a menuitem for a custom external tool.
|
|
-------------------------------------------------------------------------------}
|
|
procedure TMainIDE.mnuCustomExtToolClick(Sender: TObject);
|
|
var
|
|
Index: integer;
|
|
begin
|
|
if not (Sender is TIDEMenuItem) then exit;
|
|
Index:=itmCustomTools.IndexOf(TIDEMenuItem(Sender))-1;
|
|
if (Index<0) or (Index>=ExternalTools.Count) then exit;
|
|
DoRunExternalTool(Index,false);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEnvGeneralOptionsClicked(Sender: TObject);
|
|
begin
|
|
DoOpenIDEOptions;
|
|
end;
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
procedure TMainIDE.SaveDesktopSettings(TheEnvironmentOptions: TEnvironmentOptions);
|
|
// Called also before reading EnvironmentOptions
|
|
begin
|
|
IDEWindowCreators.SimpleLayoutStorage.StoreWindowPositions;
|
|
// do not auto show the search results view
|
|
IDEWindowCreators.SimpleLayoutStorage.ItemByFormID(
|
|
NonModalIDEWindowNames[nmiwSearchResultsViewName]).Visible:=false;
|
|
|
|
TheEnvironmentOptions.ObjectInspectorOptions.Assign(ObjectInspector1);
|
|
end;
|
|
|
|
procedure TMainIDE.LoadDesktopSettings(TheEnvironmentOptions: TEnvironmentOptions);
|
|
begin
|
|
TheEnvironmentOptions.ObjectInspectorOptions.AssignTo(ObjectInspector1);
|
|
end;
|
|
|
|
procedure TMainIDE.UpdateDefaultPascalFileExtensions;
|
|
var
|
|
DefPasExt: string;
|
|
begin
|
|
// change default pascal file extensions
|
|
DefPasExt:=PascalExtension[EnvironmentOptions.PascalFileExtension];
|
|
if LazProjectFileDescriptors<>nil then
|
|
LazProjectFileDescriptors.DefaultPascalFileExt:=DefPasExt;
|
|
end;
|
|
|
|
function TMainIDE.CreateSrcEditPageName(const AnUnitName, AFilename: string;
|
|
IgnoreEditor: TSourceEditor): string;
|
|
begin
|
|
Result:=AnUnitName;
|
|
if Result='' then
|
|
Result:=AFilename;
|
|
if FilenameIsPascalUnit(Result) then
|
|
Result:=ExtractFileNameOnly(Result)
|
|
else
|
|
Result:=ExtractFileName(Result);
|
|
Result:=SourceEditorManager.FindUniquePageName(Result,IgnoreEditor);
|
|
end;
|
|
|
|
procedure TMainIDE.OnLoadIDEOptions(Sender: TObject; AOptions: TAbstractIDEOptions);
|
|
begin
|
|
if AOptions is TEnvironmentOptions then
|
|
LoadDesktopSettings(AOptions as TEnvironmentOptions);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSaveIDEOptions(Sender: TObject; AOptions: TAbstractIDEOptions);
|
|
begin
|
|
if AOptions is TEnvironmentOptions then
|
|
SaveDesktopSettings(AOptions as TEnvironmentOptions);
|
|
end;
|
|
|
|
procedure TMainIDE.DoOpenIDEOptions(AEditor: TAbstractIDEOptionsEditorClass;
|
|
ACaption: String; AOptionsFilter: array of TAbstractIDEOptionsClass;
|
|
ASettings: TIDEOptionsEditorSettings);
|
|
var
|
|
IDEOptionsDialog: TIDEOptionsDialog;
|
|
OptionsFilter: TIDEOptionsEditorFilter;
|
|
i: Integer;
|
|
begin
|
|
IDEOptionsDialog := TIDEOptionsDialog.Create(nil);
|
|
try
|
|
if ACaption <> '' then
|
|
IDEOptionsDialog.Caption := ACaption;
|
|
if Length(AOptionsFilter) = 0 then
|
|
begin
|
|
SetLength(OptionsFilter, 1);
|
|
if AEditor <> nil then
|
|
OptionsFilter[0] := AEditor.SupportedOptionsClass
|
|
else
|
|
OptionsFilter[0] := TAbstractIDEEnvironmentOptions;
|
|
end
|
|
else
|
|
begin
|
|
SetLength(OptionsFilter, Length(AOptionsFilter));
|
|
for i := 0 to Length(AOptionsFilter) - 1 do
|
|
OptionsFilter[i] := AOptionsFilter[i];
|
|
end;
|
|
IDEOptionsDialog.OptionsFilter := OptionsFilter;
|
|
IDEOptionsDialog.Settings := ASettings;
|
|
IDEOptionsDialog.OpenEditor(AEditor);
|
|
IDEOptionsDialog.OnLoadIDEOptions:=@Self.OnLoadIDEOptions;
|
|
IDEOptionsDialog.OnSaveIDEOptions:=@Self.OnSaveIDEOptions;
|
|
IDEOptionsDialog.ReadAll;
|
|
if IDEOptionsDialog.ShowModal = mrOk then begin
|
|
IDEOptionsDialog.WriteAll(false);
|
|
UpdateHighlighters(True);
|
|
SourceEditorManager.ReloadEditorOptions;
|
|
if EnvironmentOptions.SingleTaskBarButton then
|
|
Application.TaskBarBehavior := tbSingleButton
|
|
else
|
|
Application.TaskBarBehavior := tbDefault;
|
|
end else begin
|
|
IDEOptionsDialog.WriteAll(true); // restore
|
|
end;
|
|
finally
|
|
IDEOptionsDialog.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.DoEnvironmentOptionsBeforeRead(Sender: TObject);
|
|
begin
|
|
// update EnvironmentOptions (save current window positions)
|
|
SaveDesktopSettings(EnvironmentOptions);
|
|
end;
|
|
|
|
procedure TMainIDE.DoEnvironmentOptionsBeforeWrite(Sender: TObject; Restore: boolean);
|
|
begin
|
|
if Restore then exit;
|
|
OldCompilerFilename:=EnvironmentOptions.CompilerFilename;
|
|
OldLanguage:=EnvironmentOptions.LanguageID;
|
|
end;
|
|
|
|
procedure TMainIDE.DoEnvironmentOptionsAfterWrite(Sender: TObject; Restore: boolean);
|
|
var
|
|
MacroValueChanged,
|
|
FPCSrcDirChanged, FPCCompilerChanged,
|
|
LazarusSrcDirChanged: boolean;
|
|
|
|
procedure ChangeMacroValue(const MacroName, NewValue: string);
|
|
begin
|
|
with CodeToolBoss.GlobalValues do begin
|
|
if Variables[ExternalMacroStart+MacroName]=NewValue then exit;
|
|
if Macroname='FPCSrcDir' then
|
|
FPCSrcDirChanged:=true;
|
|
if Macroname='LazarusDir' then
|
|
LazarusSrcDirChanged:=true;
|
|
Variables[ExternalMacroStart+MacroName]:=NewValue;
|
|
end;
|
|
MacroValueChanged:=true;
|
|
end;
|
|
|
|
procedure UpdateDesigners;
|
|
var
|
|
AForm: TCustomForm;
|
|
AnUnitInfo: TUnitInfo;
|
|
ADesigner: TDesigner;
|
|
begin
|
|
AnUnitInfo := Project1.FirstUnitWithComponent;
|
|
while AnUnitInfo <> nil do
|
|
begin
|
|
if (AnUnitInfo.Component<>nil) then
|
|
begin
|
|
AForm := FormEditor1.GetDesignerForm(AnUnitInfo.Component);
|
|
if AForm <> nil then
|
|
begin
|
|
ADesigner := TDesigner(AForm.Designer);
|
|
if ADesigner <> nil then
|
|
begin
|
|
ADesigner.ShowEditorHints := EnvironmentOptions.ShowEditorHints;
|
|
ADesigner.ShowComponentCaptions := EnvironmentOptions.ShowComponentCaptions;
|
|
end;
|
|
end;
|
|
end;
|
|
AnUnitInfo := AnUnitInfo.NextUnitWithComponent;
|
|
end;
|
|
InvalidateAllDesignerForms;
|
|
end;
|
|
|
|
procedure UpdateObjectInspector;
|
|
begin
|
|
EnvironmentOptions.ObjectInspectorOptions.AssignTo(ObjectInspector1);
|
|
end;
|
|
|
|
begin
|
|
if Restore then exit;
|
|
// invalidate cached substituted macros
|
|
IncreaseCompilerParseStamp;
|
|
CompileProgress.SetEnabled(EnvironmentOptions.ShowCompileDialog);
|
|
UpdateDefaultPascalFileExtensions;
|
|
if OldLanguage <> EnvironmentOptions.LanguageID then
|
|
begin
|
|
TranslateResourceStrings(EnvironmentOptions.LazarusDirectory,
|
|
EnvironmentOptions.LanguageID);
|
|
PkgBoss.TranslateResourceStrings;
|
|
end;
|
|
// set global variables
|
|
MainBuildBoss.UpdateEnglishErrorMsgFilename;
|
|
MacroValueChanged:=false;
|
|
FPCSrcDirChanged:=false;
|
|
FPCCompilerChanged:=OldCompilerFilename<>EnvironmentOptions.CompilerFilename;
|
|
LazarusSrcDirChanged:=false;
|
|
ChangeMacroValue('LazarusDir',EnvironmentOptions.LazarusDirectory);
|
|
ChangeMacroValue('FPCSrcDir',EnvironmentOptions.FPCSourceDirectory);
|
|
|
|
if MacroValueChanged then CodeToolBoss.DefineTree.ClearCache;
|
|
//debugln(['TMainIDE.DoEnvironmentOptionsAfterWrite FPCCompilerChanged=',FPCCompilerChanged,' FPCSrcDirChanged=',FPCSrcDirChanged,' LazarusSrcDirChanged=',LazarusSrcDirChanged]);
|
|
if FPCCompilerChanged or FPCSrcDirChanged then
|
|
MainBuildBoss.SetBuildTargetProject1(false);
|
|
|
|
// update environment
|
|
UpdateDesigners;
|
|
UpdateObjectInspector;
|
|
SetupHints;
|
|
Application.ShowButtonGlyphs := EnvironmentOptions.ShowButtonGlyphs;
|
|
Application.ShowMenuGlyphs := EnvironmentOptions.ShowMenuGlyphs;
|
|
|
|
// reload lazarus packages
|
|
if LazarusSrcDirChanged then
|
|
PkgBoss.LazarusSrcDirChanged;
|
|
UpdateCaption;
|
|
end;
|
|
|
|
procedure TMainIDE.DoEditorOptionsBeforeRead(Sender: TObject);
|
|
begin
|
|
// update editor options?
|
|
Project1.UpdateAllCustomHighlighter;
|
|
end;
|
|
|
|
procedure TMainIDE.DoEditorOptionsAfterWrite(Sender: TObject; Restore: boolean);
|
|
begin
|
|
if Restore then exit;
|
|
Project1.UpdateAllSyntaxHighlighter;
|
|
UpdateHighlighters(True);
|
|
SourceEditorManager.ReloadEditorOptions;
|
|
ReloadMenuShortCuts;
|
|
end;
|
|
|
|
procedure TMainIDE.DoCodetoolsOptionsAfterWrite(Sender: TObject; Restore: boolean);
|
|
begin
|
|
if Restore then exit;
|
|
CodeToolsOpts.AssignTo(CodeToolBoss);
|
|
end;
|
|
|
|
procedure TMainIDE.DoCodeExplorerOptionsAfterWrite(Sender: TObject; Restore: boolean);
|
|
begin
|
|
if Restore then exit;
|
|
if CodeExplorerView<>nil then
|
|
CodeExplorerView.Refresh(true);
|
|
end;
|
|
|
|
procedure TMainIDE.DoProjectOptionsBeforeRead(Sender: TObject);
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
AProject: TProject;
|
|
begin
|
|
//debugln(['TMainIDE.DoProjectOptionsBeforeRead ',DbgSName(Sender)]);
|
|
BeginCodeTool(ActiveSrcEdit, ActiveUnitInfo, []);
|
|
AProject:=TProject(Sender);
|
|
AProject.BackupSession;
|
|
AProject.BackupBuildModes;
|
|
AProject.UpdateExecutableType;
|
|
AProject.CompilerOptions.UseAsDefault := False;
|
|
end;
|
|
|
|
procedure TMainIDE.DoProjectOptionsAfterWrite(Sender: TObject; Restore: boolean);
|
|
var
|
|
AProject: TProject absolute Sender;
|
|
aFilename: String;
|
|
|
|
function GetTitle: String;
|
|
begin
|
|
Result := '';
|
|
if (AProject = nil) or (AProject.MainUnitID < 0) then
|
|
Exit;
|
|
CodeToolBoss.GetApplicationTitleStatement(AProject.MainUnitInfo.Source, Result);
|
|
end;
|
|
|
|
function SetTitle: Boolean;
|
|
var
|
|
OldTitle: String;
|
|
begin
|
|
Result := True;
|
|
if (AProject.MainUnitID < 0) or
|
|
(not (pfMainUnitHasTitleStatement in AProject.Flags)) then
|
|
Exit;
|
|
OldTitle := GetTitle;
|
|
if (OldTitle = '') and AProject.TitleIsDefault then
|
|
Exit;
|
|
|
|
if (OldTitle <> AProject.Title) and (not AProject.TitleIsDefault) then
|
|
if not CodeToolBoss.SetApplicationTitleStatement(AProject.MainUnitInfo.Source, AProject.Title) then
|
|
begin
|
|
MessageDlg(lisProjOptsError,
|
|
Format(lisUnableToChangeProjectTitleInSource, [#13, CodeToolBoss.
|
|
ErrorMessage]),
|
|
mtWarning, [mbOk], 0);
|
|
Result := False;
|
|
Exit;
|
|
end;// set Application.Title:= statement
|
|
|
|
if (OldTitle <> '') and AProject.TitleIsDefault then
|
|
if not CodeToolBoss.RemoveApplicationTitleStatement(AProject.MainUnitInfo.Source) then
|
|
begin
|
|
MessageDlg(lisProjOptsError,
|
|
Format(lisUnableToRemoveProjectTitleFromSource, [#13, CodeToolBoss.
|
|
ErrorMessage]),
|
|
mtWarning, [mbOk], 0);
|
|
Result := False;
|
|
Exit;
|
|
end;// delete title
|
|
end;
|
|
|
|
function SetAutoCreateForms: boolean;
|
|
var
|
|
i: integer;
|
|
OldList: TStrings;
|
|
begin
|
|
Result := True;
|
|
if (AProject.MainUnitID < 0) or
|
|
(not (pfMainUnitHasUsesSectionForAllUnits in AProject.Flags)) then
|
|
Exit;
|
|
OldList := AProject.GetAutoCreatedFormsList;
|
|
if (OldList = nil) then
|
|
Exit;
|
|
try
|
|
if OldList.Count = AProject.TmpAutoCreatedForms.Count then
|
|
begin
|
|
|
|
{ Just exit if the form list is the same }
|
|
i := OldList.Count - 1;
|
|
while (i >= 0) and (SysUtils.CompareText(OldList[i], AProject.TmpAutoCreatedForms[i]) = 0) do
|
|
Dec(i);
|
|
if i < 0 then
|
|
Exit;
|
|
end;
|
|
|
|
if not CodeToolBoss.SetAllCreateFromStatements(AProject.MainUnitInfo.Source,
|
|
AProject.TmpAutoCreatedForms) then
|
|
begin
|
|
MessageDlg(lisProjOptsError,
|
|
Format(lisProjOptsUnableToChangeTheAutoCreateFormList, [LineEnding]),
|
|
mtWarning, [mbOK], 0);
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
finally
|
|
OldList.Free;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
//debugln(['TMainIDE.DoProjectOptionsAfterWrite ',DbgSName(Sender),' Restore=',Restore]);
|
|
if not Restore then
|
|
begin
|
|
SetTitle;
|
|
SetAutoCreateForms;
|
|
// extend include path
|
|
AProject.AutoAddOutputDirToIncPath;
|
|
if AProject.ProjResources.Modified and (AProject.MainUnitID >= 0) then
|
|
begin
|
|
if not AProject.ProjResources.Regenerate(AProject.MainFilename, True, False, '') then
|
|
MessageDlg(AProject.ProjResources.Messages.Text, mtWarning, [mbOk], 0);
|
|
end;
|
|
UpdateCaption;
|
|
AProject.DefineTemplates.AllChanged;
|
|
end;
|
|
if Restore then
|
|
AProject.RestoreBuildModes;
|
|
IncreaseCompilerParseStamp;
|
|
MainBuildBoss.SetBuildTargetProject1(false);
|
|
if (not Restore) and AProject.CompilerOptions.UseAsDefault then
|
|
begin
|
|
aFilename:=AppendPathDelim(GetPrimaryConfigPath)+DefaultProjectCompilerOptionsFilename;
|
|
AProject.CompilerOptions.SaveToFile(aFilename);
|
|
end;
|
|
if Restore then
|
|
AProject.RestoreSession;
|
|
end;
|
|
|
|
procedure TMainIDE.ComponentPaletteClassSelected(Sender: TObject);
|
|
begin
|
|
if (Screen.CustomFormZOrderCount > 1)
|
|
and Assigned(Screen.CustomFormsZOrdered[1].Designer) then begin
|
|
// previous active form was designer form
|
|
ShowDesignerForm(Screen.CustomFormsZOrdered[1]);
|
|
Exit;
|
|
end;
|
|
DoShowDesignerFormOfCurrentSrc;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEnvEditorOptionsClicked(Sender: TObject);
|
|
begin
|
|
DoOpenIDEOptions(TEditorGeneralOptionsFrame);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEnvCodeTemplatesClicked(Sender: TObject);
|
|
begin
|
|
if ShowCodeTemplateDialog=mrOk then begin
|
|
UpdateHighlighters(True);
|
|
SourceEditorManager.ReloadEditorOptions;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEnvCodeToolsDefinesEditorClicked(Sender: TObject);
|
|
begin
|
|
ShowCodeToolsDefinesEditor(CodeToolBoss,CodeToolsOpts,GlobalMacroList);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEnvRescanFPCSrcDirClicked(Sender: TObject);
|
|
begin
|
|
IncreaseBuildMacroChangeStamp;
|
|
MainBuildBoss.RescanCompilerDefines(false,true,false,false);
|
|
end;
|
|
|
|
procedure TMainIDE.SaveEnvironment;
|
|
begin
|
|
SaveDesktopSettings(EnvironmentOptions);
|
|
EnvironmentOptions.Save(false);
|
|
//debugln('TMainIDE.SaveEnvironment A ',dbgsName(ObjectInspector1.Favourites));
|
|
if (ObjectInspector1<>nil) and (ObjectInspector1.Favourites<>nil) then
|
|
SaveOIFavouriteProperties(ObjectInspector1.Favourites);
|
|
end;
|
|
|
|
//==============================================================================
|
|
|
|
function TMainIDE.CreateNewCodeBuffer(Descriptor: TProjectFileDescriptor;
|
|
NewOwner: TObject; NewFilename: string;
|
|
var NewCodeBuffer: TCodeBuffer; var NewUnitName: string): TModalResult;
|
|
var
|
|
NewShortFilename: String;
|
|
NewFileExt: String;
|
|
SearchFlags: TSearchIDEFileFlags;
|
|
begin
|
|
//debugln('TMainIDE.CreateNewCodeBuffer START NewFilename=',NewFilename,' ',Descriptor.DefaultFilename,' ',Descriptor.ClassName);
|
|
NewUnitName:='';
|
|
NewCodeBuffer:=nil;
|
|
if NewFilename='' then begin
|
|
// create a new unique filename
|
|
SearchFlags:=[siffCheckAllProjects];
|
|
if Descriptor.IsPascalUnit then begin
|
|
if NewUnitName='' then
|
|
NewUnitName:=Descriptor.DefaultSourceName;
|
|
NewShortFilename:=lowercase(NewUnitName);
|
|
NewFileExt:=Descriptor.DefaultFileExt;
|
|
SearchFlags:=SearchFlags+[siffIgnoreExtension];
|
|
end else begin
|
|
NewFilename:=ExtractFilename(Descriptor.DefaultFilename);
|
|
NewShortFilename:=ExtractFilenameOnly(NewFilename);
|
|
NewFileExt:=ExtractFileExt(NewFilename);
|
|
SearchFlags:=[];
|
|
end;
|
|
NewFilename:=CreateNewUniqueFilename(NewShortFilename,NewFileExt,NewOwner,
|
|
SearchFlags,true);
|
|
if NewFilename='' then
|
|
RaiseException('');
|
|
NewShortFilename:=ExtractFilenameOnly(NewFilename);
|
|
// use as unitname the NewShortFilename, but with the case of the
|
|
// original unitname. e.g. 'unit12.pas' becomes 'Unit12.pas'
|
|
if Descriptor.IsPascalUnit then begin
|
|
NewUnitName:=ChompEndNumber(NewUnitName);
|
|
NewUnitName:=NewUnitName+copy(NewShortFilename,length(NewUnitName)+1,
|
|
length(NewShortFilename));
|
|
end;
|
|
end;
|
|
//debugln('TMainIDE.CreateNewCodeBuffer NewFilename=',NewFilename,' NewUnitName=',NewUnitName);
|
|
|
|
if FilenameIsPascalUnit(NewFilename) then begin
|
|
if NewUnitName='' then
|
|
NewUnitName:=ExtractFileNameOnly(NewFilename);
|
|
if EnvironmentOptions.CharcaseFileAction in [ccfaAsk, ccfaAutoRename] then
|
|
NewFilename:=ExtractFilePath(NewFilename)
|
|
+lowercase(ExtractFileName(NewFilename));
|
|
end;
|
|
|
|
NewCodeBuffer:=CodeToolBoss.CreateFile(NewFilename);
|
|
if NewCodeBuffer=nil then
|
|
exit(mrCancel);
|
|
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.CreateNewForm(NewUnitInfo: TUnitInfo;
|
|
AncestorType: TPersistentClass; ResourceCode: TCodeBuffer;
|
|
UseCreateFormStatements, DisableAutoSize: Boolean): TModalResult;
|
|
var
|
|
NewComponent: TComponent;
|
|
new_x, new_y: integer;
|
|
p: TPoint;
|
|
r: TRect;
|
|
begin
|
|
if not AncestorType.InheritsFrom(TComponent) then
|
|
RaiseException('TMainIDE.CreateNewForm invalid AncestorType');
|
|
|
|
//debugln('TMainIDE.CreateNewForm START ',NewUnitInfo.Filename,' ',AncestorType.ClassName,' ',dbgs(ResourceCode<>nil));
|
|
// create a buffer for the new resource file and for the LFM file
|
|
if ResourceCode=nil then begin
|
|
ResourceCode:=
|
|
CodeToolBoss.CreateFile(ChangeFileExt(NewUnitInfo.Filename,
|
|
ResourceFileExt));
|
|
end;
|
|
//debugln('TMainIDE.CreateNewForm B ',ResourceCode.Filename);
|
|
ResourceCode.Source:='{ '+LRSComment+' }';
|
|
CodeToolBoss.CreateFile(ChangeFileExt(NewUnitInfo.Filename,'.lfm'));
|
|
|
|
// clear formeditor
|
|
FormEditor1.ClearSelection;
|
|
|
|
// Figure out where we want to put the new form
|
|
// if there is more place left of the OI put it left, otherwise right
|
|
p:=ObjectInspector1.ClientOrigin;
|
|
new_x:=p.X;
|
|
if new_x>Screen.Width div 2 then
|
|
new_x:=new_x-500
|
|
else
|
|
new_x:=new_x+ObjectInspector1.Width;
|
|
new_y:=p.Y+10;
|
|
r:=Screen.PrimaryMonitor.WorkareaRect;
|
|
new_x:=Max(r.Left,Min(new_x,r.Right-200));
|
|
new_y:=Max(r.Top,Min(new_y,r.Bottom-200));
|
|
|
|
// create jit component
|
|
NewComponent := FormEditor1.CreateComponent(nil,TComponentClass(AncestorType),
|
|
NewUnitInfo.CreateUnitName, new_x, new_y, 0,0,DisableAutoSize);
|
|
if NewComponent=nil then begin
|
|
DebugLn(['TMainIDE.CreateNewForm FormEditor1.CreateComponent failed ',dbgsName(TComponentClass(AncestorType))]);
|
|
exit(mrCancel);
|
|
end;
|
|
FormEditor1.SetComponentNameAndClass(NewComponent,
|
|
NewUnitInfo.ComponentName,'T'+NewUnitInfo.ComponentName);
|
|
if NewComponent is TCustomForm then
|
|
TControl(NewComponent).Visible := False;
|
|
if (NewComponent is TControl)
|
|
and (csSetCaption in TControl(NewComponent).ControlStyle) then
|
|
TControl(NewComponent).Caption:=NewComponent.Name;
|
|
NewUnitInfo.Component := NewComponent;
|
|
CreateDesignerForComponent(NewUnitInfo,NewComponent);
|
|
|
|
NewUnitInfo.ComponentName:=NewComponent.Name;
|
|
NewUnitInfo.ComponentResourceName:=NewUnitInfo.ComponentName;
|
|
if UseCreateFormStatements and
|
|
NewUnitInfo.IsPartOfProject and
|
|
Project1.AutoCreateForms and
|
|
(pfMainUnitHasCreateFormStatements in Project1.Flags) then
|
|
begin
|
|
Project1.AddCreateFormToProjectFile(NewComponent.ClassName,
|
|
NewComponent.Name);
|
|
end;
|
|
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoLoadResourceFile(AnUnitInfo: TUnitInfo;
|
|
var LFMCode, ResourceCode: TCodeBuffer;
|
|
IgnoreSourceErrors, AutoCreateResourceCode, ShowAbort: boolean): TModalResult;
|
|
var
|
|
LFMFilename: string;
|
|
LRSFilename: String;
|
|
ResType: TResourceType;
|
|
begin
|
|
LFMCode:=nil;
|
|
ResourceCode:=nil;
|
|
//DebugLn(['TMainIDE.DoLoadResourceFile ',AnUnitInfo.Filename,' HasResources=',AnUnitInfo.HasResources,' IgnoreSourceErrors=',IgnoreSourceErrors,' AutoCreateResourceCode=',AutoCreateResourceCode]);
|
|
if AnUnitInfo.HasResources then begin
|
|
//writeln('TMainIDE.DoLoadResourceFile A "',AnUnitInfo.Filename,'" "',AnUnitInfo.ResourceFileName,'"');
|
|
|
|
ResType:=MainBuildBoss.GetResourceType(AnUnitInfo);
|
|
if ResType=rtLRS then begin
|
|
LRSFilename:=MainBuildBoss.FindLRSFilename(AnUnitInfo,false);
|
|
if LRSFilename<>'' then begin
|
|
Result:=LoadCodeBuffer(ResourceCode,LRSFilename,[lbfUpdateFromDisk],ShowAbort);
|
|
if Result<>mrOk then exit;
|
|
end else begin
|
|
LRSFilename:=MainBuildBoss.GetDefaultLRSFilename(AnUnitInfo);
|
|
if AutoCreateResourceCode then begin
|
|
ResourceCode:=CodeToolBoss.CreateFile(LRSFilename);
|
|
end else begin
|
|
DebugLn(['TMainIDE.DoLoadResourceFile .lrs file not found of unit ',AnUnitInfo.Filename]);
|
|
exit(mrCancel);
|
|
end;
|
|
end;
|
|
end else begin
|
|
LRSFilename:='';
|
|
ResourceCode:=nil;
|
|
end;
|
|
|
|
// if no resource file found (i.e. normally the .lrs file)
|
|
// don't bother the user, because it is created automatically anyway
|
|
|
|
// then load the lfm file (without parsing)
|
|
if (not AnUnitInfo.IsVirtual) and (AnUnitInfo.Component<>nil) then begin
|
|
LFMFilename:=ChangeFileExt(AnUnitInfo.Filename,'.lfm');
|
|
if not FileExistsUTF8(LFMFilename) then
|
|
LFMFilename:=ChangeFileExt(AnUnitInfo.Filename,'.dfm');
|
|
if (FileExistsUTF8(LFMFilename)) then begin
|
|
Result:=LoadCodeBuffer(LFMCode,LFMFilename,[lbfCheckIfText],ShowAbort);
|
|
if not (Result in [mrOk,mrIgnore]) then exit;
|
|
end;
|
|
end;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoOpenComponent(const UnitFilename: string;
|
|
OpenFlags: TOpenFlags; CloseFlags: TCloseFlags;
|
|
out Component: TComponent): TModalResult;
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
LFMFilename: String;
|
|
UnitCode: TCodeBuffer;
|
|
LFMCode: TCodeBuffer;
|
|
AFilename: String;
|
|
begin
|
|
// try to find a unit name without expaning the path. this is required if unit is virtual
|
|
// in other case file name will be expanded with the wrong path
|
|
AFilename := UnitFilename;
|
|
AnUnitInfo:=Project1.UnitInfoWithFilename(AFilename);
|
|
if AnUnitInfo = nil then
|
|
begin
|
|
AFilename:=TrimAndExpandFilename(UnitFilename);
|
|
if (AFilename='') or (not FileExistsInIDE(AFilename,[])) then begin
|
|
DebugLn(['TMainIDE.DoOpenComponent file not found ',AFilename]);
|
|
exit(mrCancel);
|
|
end;
|
|
AnUnitInfo:=Project1.UnitInfoWithFilename(AFilename);
|
|
end;
|
|
if (not (ofRevert in OpenFlags))
|
|
and (AnUnitInfo<>nil) and (AnUnitInfo.Component<>nil) then begin
|
|
// already open
|
|
Component:=AnUnitInfo.Component;
|
|
Result:=mrOk;
|
|
exit;
|
|
end;
|
|
|
|
LFMFilename:=ChangeFileExt(AFilename,'.lfm');
|
|
if not FileExistsInIDE(LFMFilename,[]) then
|
|
LFMFilename:=ChangeFileExt(AFilename,'.dfm');
|
|
if not FileExistsInIDE(LFMFilename,[]) then begin
|
|
DebugLn(['TMainIDE.DoOpenComponent file not found ',LFMFilename]);
|
|
exit(mrCancel);
|
|
end;
|
|
|
|
// load unit source
|
|
Result:=LoadCodeBuffer(UnitCode,AFilename,[lbfCheckIfText],true);
|
|
if Result<>mrOk then begin
|
|
debugln('TMainIDE.DoOpenComponent Failed loading ',AFilename);
|
|
exit;
|
|
end;
|
|
|
|
// create unit info
|
|
if AnUnitInfo=nil then begin
|
|
AnUnitInfo:=TUnitInfo.Create(UnitCode);
|
|
AnUnitInfo.ReadUnitNameFromSource(true);
|
|
Project1.AddFile(AnUnitInfo,false);
|
|
end;
|
|
|
|
// load lfm source
|
|
Result:=LoadCodeBuffer(LFMCode,LFMFilename,[lbfCheckIfText],true);
|
|
if Result<>mrOk then begin
|
|
debugln('TMainIDE.DoOpenComponent Failed loading ',LFMFilename);
|
|
exit;
|
|
end;
|
|
|
|
// load resource
|
|
Result:=DoLoadLFM(AnUnitInfo,LFMCode,OpenFlags,CloseFlags);
|
|
if Result<>mrOk then begin
|
|
debugln('TMainIDE.DoOpenComponent DoLoadLFM failed ',LFMFilename);
|
|
exit;
|
|
end;
|
|
|
|
Component:=AnUnitInfo.Component;
|
|
if Component<>nil then
|
|
Result:=mrOk
|
|
else
|
|
Result:=mrCancel;
|
|
end;
|
|
|
|
function TMainIDE.DoShowSaveFileAsDialog(var AFilename: string;
|
|
AnUnitInfo: TUnitInfo;
|
|
var ResourceCode: TCodeBuffer; CanAbort: boolean): TModalResult;
|
|
var
|
|
SaveDialog: TSaveDialog;
|
|
SaveAsFilename, SaveAsFileExt, NewFilename, NewUnitName, NewFilePath,
|
|
AlternativeUnitName: string;
|
|
ACaption, AText: string;
|
|
SrcEdit: TSourceEditor;
|
|
FileWithoutPath: String;
|
|
PkgDefaultDirectory: String;
|
|
OldUnitName: String;
|
|
IsPascal: Boolean;
|
|
Filter: String;
|
|
AllEditorExt: string;
|
|
AllFilter: string;
|
|
begin
|
|
if (AnUnitInfo<>nil) and (AnUnitInfo.OpenEditorInfoCount>0) then
|
|
SrcEdit := TSourceEditor(AnUnitInfo.OpenEditorInfo[0].EditorComponent)
|
|
else
|
|
SrcEdit:=nil;
|
|
//debugln('TMainIDE.DoShowSaveFileAsDialog ',AnUnitInfo.Filename);
|
|
|
|
// try to keep the old filename and extension
|
|
SaveAsFileExt:=ExtractFileExt(AFileName);
|
|
if (SaveAsFileExt='') and (SrcEdit<>nil) then begin
|
|
if (SrcEdit.SyntaxHighlighterType in [lshFreePascal, lshDelphi])
|
|
then
|
|
SaveAsFileExt:=PascalExtension[EnvironmentOptions.PascalFileExtension]
|
|
else
|
|
SaveAsFileExt:=EditorOpts.HighlighterList.GetDefaultFilextension(
|
|
SrcEdit.SyntaxHighlighterType);
|
|
end;
|
|
IsPascal:=FilenameIsPascalSource(AFilename);
|
|
if IsPascal then begin
|
|
if AnUnitInfo<>nil then
|
|
OldUnitName:=AnUnitInfo.ParseUnitNameFromSource(false)
|
|
else
|
|
OldUnitName:=ExtractFileNameOnly(AFilename);
|
|
end else
|
|
OldUnitName:='';
|
|
//debugln('TMainIDE.DoShowSaveFileAsDialog sourceunitname=',OldUnitName);
|
|
SaveAsFilename:=OldUnitName;
|
|
if SaveAsFilename='' then
|
|
SaveAsFilename:=ExtractFileNameOnly(AFilename);
|
|
if SaveAsFilename='' then
|
|
SaveAsFilename:=lisnoname;
|
|
|
|
//suggest lowercased name if user wants so
|
|
if EnvironmentOptions.LowercaseDefaultFilename = true then
|
|
SaveAsFilename:=LowerCase(SaveAsFilename);
|
|
|
|
// let user choose a filename
|
|
SaveDialog:=TSaveDialog.Create(nil);
|
|
try
|
|
InputHistories.ApplyFileDialogSettings(SaveDialog);
|
|
SaveDialog.Title:=lisSaveSpace+SaveAsFilename+' (*'+SaveAsFileExt+')';
|
|
SaveDialog.FileName:=SaveAsFilename+SaveAsFileExt;
|
|
|
|
Filter := lisLazarusUnit + ' (*.pas;*.pp)|*.pas;*.pp';
|
|
if (SaveAsFileExt='.lpi') then
|
|
Filter:=Filter+ '|' + lisLazarusProject + ' (*.lpi)|*.lpi';
|
|
if (SaveAsFileExt='.lfm') or (SaveAsFileExt='.dfm') then
|
|
Filter:=Filter+ '|' + lisLazarusForm + ' (*.lfm;*.dfm)|*.lfm;*.dfm';
|
|
if (SaveAsFileExt='.lpk') then
|
|
Filter:=Filter+ '|' + lisLazarusPackage + ' (*.lpk)|*.lpk';
|
|
if (SaveAsFileExt='.lpr') then
|
|
Filter:=Filter+ '|' + lisLazarusProjectSource + ' (*.lpr)|*.lpr';
|
|
// append a filter for all editor files
|
|
CreateFileDialogFilterForSourceEditorFiles(Filter,AllEditorExt,AllFilter);
|
|
if AllEditorExt<>'' then
|
|
Filter:=Filter+ '|' + lisEditorFileTypes + ' (' + AllEditorExt + ')|' +
|
|
AllEditorExt;
|
|
|
|
// append an any file filter *.*
|
|
Filter:=Filter+ '|' + dlgAllFiles + ' (' + GetAllFilesMask + ')|' + GetAllFilesMask;
|
|
|
|
// prepend an all filter
|
|
Filter:= lisLazarusFile + ' ('+AllFilter+')|' + AllFilter + '|' + Filter;
|
|
SaveDialog.Filter := Filter;
|
|
|
|
// if this is a project file, start in project directory
|
|
if (AnUnitInfo=nil)
|
|
or (AnUnitInfo.IsPartOfProject and (not Project1.IsVirtual)
|
|
and (not FileIsInPath(SaveDialog.InitialDir,Project1.ProjectDirectory)))
|
|
then begin
|
|
SaveDialog.InitialDir:=Project1.ProjectDirectory;
|
|
end;
|
|
// if this is a package file, then start in package directory
|
|
PkgDefaultDirectory:=
|
|
PkgBoss.GetDefaultSaveDirectoryForFile(AFilename);
|
|
if (PkgDefaultDirectory<>'')
|
|
and (not FileIsInPath(SaveDialog.InitialDir,PkgDefaultDirectory)) then
|
|
SaveDialog.InitialDir:=PkgDefaultDirectory;
|
|
// show save dialog
|
|
if (not SaveDialog.Execute) or (ExtractFileName(SaveDialog.Filename)='')
|
|
then begin
|
|
// user cancels
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
NewFilename:=ExpandFileNameUTF8(SaveDialog.Filename);
|
|
finally
|
|
InputHistories.StoreFileDialogSettings(SaveDialog);
|
|
SaveDialog.Free;
|
|
end;
|
|
|
|
// check file extension
|
|
if ExtractFileExt(NewFilename)='' then begin
|
|
NewFilename:=NewFilename+SaveAsFileExt;
|
|
end;
|
|
|
|
// check file path
|
|
NewFilePath:=ExtractFilePath(NewFilename);
|
|
if not DirPathExists(NewFilePath) then begin
|
|
ACaption:=lisEnvOptDlgDirectoryNotFound;
|
|
AText:=Format(lisTheDestinationDirectoryDoesNotExist, [#13, '"',
|
|
NewFilePath, '"']);
|
|
Result:=IDEMessageDialogAb(ACaption, AText, mtConfirmation,[mbCancel],CanAbort);
|
|
exit;
|
|
end;
|
|
|
|
// check unitname
|
|
if FilenameIsPascalUnit(NewFilename) then begin
|
|
NewUnitName:=ExtractFileNameOnly(NewFilename);
|
|
// do not rename the unit if new filename differs from its name only in case
|
|
if LowerCase(OldUnitName)=NewUnitName then
|
|
NewUnitName:=OldUnitName;
|
|
if NewUnitName='' then begin
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
if not IsValidIdent(NewUnitName) then begin
|
|
AlternativeUnitName:=NameToValidIdentifier(NewUnitName);
|
|
Result:=IDEMessageDialogAb(lisInvalidPascalIdentifierCap,
|
|
Format(lisInvalidPascalIdentifierText,[NewUnitName,AlternativeUnitName]),
|
|
mtWarning,[mbIgnore,mbCancel],CanAbort);
|
|
if Result in [mrCancel,mrAbort] then exit;
|
|
NewUnitName:=AlternativeUnitName;
|
|
Result:=mrCancel;
|
|
end;
|
|
if Project1.IndexOfUnitWithName(NewUnitName,true,AnUnitInfo)>=0 then
|
|
begin
|
|
Result:=IDEQuestionDialogAb(lisUnitNameAlreadyExistsCap,
|
|
Format(lisTheUnitAlreadyExistsIgnoreWillForceTheRenaming, ['"',
|
|
NewUnitName, '"', #13, #13, #13]),
|
|
mtConfirmation, [mrIgnore, lisForceRenaming,
|
|
mrCancel, lisCancelRenaming,
|
|
mrAbort, lisAbortAll], not CanAbort);
|
|
if Result=mrIgnore then
|
|
Result:=mrCancel
|
|
else
|
|
exit;
|
|
end;
|
|
end else begin
|
|
NewUnitName:='';
|
|
end;
|
|
|
|
// check filename
|
|
if FilenameIsPascalUnit(NewFilename) then begin
|
|
FileWithoutPath:=ExtractFileName(NewFilename);
|
|
// check if file should be auto renamed
|
|
|
|
if EnvironmentOptions.CharcaseFileAction = ccfaAsk then begin
|
|
if lowercase(FileWithoutPath)<>FileWithoutPath
|
|
then begin
|
|
Result:=IDEQuestionDialogAb(lisRenameFile,
|
|
Format(lisThisLooksLikeAPascalFileItIsRecommendedToUseLowerC, [
|
|
#13, #13]),
|
|
mtWarning, [mrYes, lisRenameToLowercase, mrNoToAll, lisKeepName,
|
|
mrAbort, lisAbortAll], not CanAbort);
|
|
if Result=mrYes then
|
|
NewFileName:=ExtractFilePath(NewFilename)+lowercase(FileWithoutPath);
|
|
Result:=mrOk;
|
|
end;
|
|
end else begin
|
|
if EnvironmentOptions.CharcaseFileAction = ccfaAutoRename then
|
|
NewFileName:=ExtractFilePath(NewFilename)+lowercase(FileWithoutPath);
|
|
end;
|
|
end;
|
|
|
|
// check overwrite existing file
|
|
if ((not FilenameIsAbsolute(AFilename))
|
|
or (CompareFilenames(NewFilename,AFilename)<>0))
|
|
and FileExistsUTF8(NewFilename) then begin
|
|
ACaption:=lisOverwriteFile;
|
|
AText:=Format(lisAFileAlreadyExistsReplaceIt, ['"', NewFilename, '"', #13]);
|
|
Result:=IDEQuestionDialogAb(ACaption, AText, mtConfirmation,
|
|
[mrYes, lisOverwriteFileOnDisk, mrCancel,
|
|
mrAbort, lisAbortAll], not CanAbort);
|
|
if Result=mrCancel then exit;
|
|
end;
|
|
|
|
if AnUnitInfo<>nil then begin
|
|
// rename unit
|
|
Result:=DoRenameUnit(AnUnitInfo,NewFilename,NewUnitName,ResourceCode);
|
|
AFilename:=AnUnitInfo.Filename;
|
|
if Result<>mrOk then exit;
|
|
end else begin
|
|
Result:=mrOk;
|
|
AFilename:=NewFilename;
|
|
end;
|
|
end;
|
|
|
|
{ TLRTGrubber }
|
|
type
|
|
TLRTGrubber = class(TObject)
|
|
private
|
|
FGrubbed: TStrings;
|
|
FWriter: TWriter;
|
|
public
|
|
constructor Create(TheWriter: TWriter);
|
|
destructor Destroy; override;
|
|
procedure Grub(Sender: TObject; const Instance: TPersistent;
|
|
PropInfo: PPropInfo; var Content: string);
|
|
property Grubbed: TStrings read FGrubbed;
|
|
property Writer: TWriter read FWriter write FWriter;
|
|
end;
|
|
|
|
constructor TLRTGrubber.Create(TheWriter: TWriter);
|
|
begin
|
|
inherited Create;
|
|
FGrubbed:=TStringList.Create;
|
|
FWriter:=TheWriter;
|
|
FWriter.OnWriteStringProperty:=@Grub;
|
|
end;
|
|
|
|
destructor TLRTGrubber.Destroy;
|
|
begin
|
|
FGrubbed.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TLRTGrubber.Grub(Sender: TObject; const Instance: TPersistent;
|
|
PropInfo: PPropInfo; var Content: string);
|
|
var
|
|
LRSWriter: TLRSObjectWriter;
|
|
Path: String;
|
|
begin
|
|
if not Assigned(Instance) then exit;
|
|
if not Assigned(PropInfo) then exit;
|
|
if SysUtils.CompareText(PropInfo^.PropType^.Name,'TTRANSLATESTRING')<>0 then exit;
|
|
if Writer.Driver is TLRSObjectWriter then begin
|
|
LRSWriter:=TLRSObjectWriter(Writer.Driver);
|
|
Path:=LRSWriter.GetStackPath;
|
|
end else begin
|
|
Path:=Instance.ClassName+'.'+PropInfo^.Name;
|
|
end;
|
|
|
|
FGrubbed.Add(Uppercase(Path)+'='+Content);
|
|
//DebugLn(['TLRTGrubber.Grub "',FGrubbed[FGrubbed.Count-1],'"']);
|
|
end;
|
|
|
|
function TMainIDE.DoSaveUnitComponent(AnUnitInfo: TUnitInfo;
|
|
ResourceCode, LFMCode: TCodeBuffer; Flags: TSaveFlags): TModalResult;
|
|
var
|
|
ComponentSavingOk: boolean;
|
|
MemStream, BinCompStream, TxtCompStream: TExtMemoryStream;
|
|
DestroyDriver: Boolean;
|
|
Writer: TWriter;
|
|
ACaption, AText: string;
|
|
CompResourceCode, LFMFilename, TestFilename: string;
|
|
ADesigner: TDesigner;
|
|
Grubber: TLRTGrubber;
|
|
LRTFilename: String;
|
|
AncestorUnit: TUnitInfo;
|
|
Ancestor: TComponent;
|
|
HasI18N: Boolean;
|
|
UnitOwners: TFPList;
|
|
APackage: TLazPackage;
|
|
i: Integer;
|
|
LRSFilename: String;
|
|
PropPath: String;
|
|
ResType: TResourceType;
|
|
begin
|
|
Result:=mrCancel;
|
|
|
|
// save lrs - lazarus resource file and lfm - lazarus form text file
|
|
// Note: When there is a bug in the source, the include directive of the
|
|
// resource code can not be found, therefore the LFM file should always
|
|
// be saved first.
|
|
// And therefore each TUnitInfo stores the resource filename (.lrs).
|
|
|
|
// the lfm file is saved before the lrs file, because the IDE only needs the
|
|
// lfm file to recreate the lrs file.
|
|
// by VVI - now a LRT file is saved in addition to LFM and LRS
|
|
// LRT file format (in present) are lines
|
|
// <ClassName>.<PropertyName>=<PropertyValue>
|
|
LRSFilename:='';
|
|
ResType:=MainBuildBoss.GetResourceType(AnUnitInfo);
|
|
ResourceCode:=nil;
|
|
|
|
if (AnUnitInfo.Component<>nil) then begin
|
|
// stream component to resource code and to lfm file
|
|
ComponentSavingOk:=true;
|
|
|
|
// clean up component
|
|
Result:=DoRemoveDanglingEvents(AnUnitInfo,true);
|
|
if Result<>mrOk then exit;
|
|
|
|
// save designer form properties to the component
|
|
FormEditor1.SaveHiddenDesignerFormProperties(AnUnitInfo.Component);
|
|
|
|
if ResType=rtLRS then begin
|
|
if (sfSaveToTestDir in Flags) then
|
|
LRSFilename:=MainBuildBoss.GetDefaultLRSFilename(AnUnitInfo)
|
|
else
|
|
LRSFilename:=MainBuildBoss.FindLRSFilename(AnUnitInfo,true);
|
|
end;
|
|
|
|
// stream component to binary stream
|
|
BinCompStream:=TExtMemoryStream.Create;
|
|
if AnUnitInfo.ComponentLastBinStreamSize>0 then
|
|
BinCompStream.Capacity:=
|
|
AnUnitInfo.ComponentLastBinStreamSize+LRSStreamChunkSize;
|
|
Writer:=nil;
|
|
DestroyDriver:=false;
|
|
Grubber:=nil;
|
|
UnitOwners:=nil;
|
|
try
|
|
UnitOwners:=PkgBoss.GetOwnersOfUnit(AnUnitInfo.Filename);
|
|
Result:=mrOk;
|
|
repeat
|
|
try
|
|
BinCompStream.Position:=0;
|
|
Writer:=CreateLRSWriter(BinCompStream,DestroyDriver);
|
|
// used to save lrt files
|
|
HasI18N:=AnUnitInfo.IsPartOfProject and (not AnUnitInfo.DisableI18NForLFM)
|
|
and AnUnitInfo.Project.EnableI18N and AnUnitInfo.Project.EnableI18NForLFM;
|
|
if (not HasI18N) and (UnitOwners<>nil) then begin
|
|
for i:=0 to UnitOwners.Count-1 do begin
|
|
if TObject(UnitOwners[i]) is TLazPackage then begin
|
|
APackage:=TLazPackage(UnitOwners[i]);
|
|
if APackage.EnableI18N then
|
|
HasI18N:=true;
|
|
end;
|
|
end;
|
|
end;
|
|
if HasI18N then
|
|
Grubber:=TLRTGrubber.Create(Writer);
|
|
Writer.OnWriteMethodProperty:=@FormEditor1.WriteMethodPropertyEvent;
|
|
//DebugLn(['TMainIDE.DoSaveUnitComponent AncestorInstance=',dbgsName(AncestorInstance)]);
|
|
Writer.OnFindAncestor:=@FormEditor1.WriterFindAncestor;
|
|
AncestorUnit:=AnUnitInfo.FindAncestorUnit;
|
|
Ancestor:=nil;
|
|
if AncestorUnit<>nil then
|
|
Ancestor:=AncestorUnit.Component;
|
|
//DebugLn(['TMainIDE.DoSaveUnitComponent Writer.WriteDescendent ARoot=',AnUnitInfo.Component,' Ancestor=',DbgSName(Ancestor)]);
|
|
Writer.WriteDescendent(AnUnitInfo.Component,Ancestor);
|
|
if DestroyDriver then Writer.Driver.Free;
|
|
FreeAndNil(Writer);
|
|
AnUnitInfo.ComponentLastBinStreamSize:=BinCompStream.Size;
|
|
except
|
|
on E: Exception do begin
|
|
PropPath:='';
|
|
if Writer.Driver is TLRSObjectWriter then
|
|
PropPath:=TLRSObjectWriter(Writer.Driver).GetStackPath;
|
|
DumpExceptionBackTrace;
|
|
ACaption:=lisStreamingError;
|
|
AText:=Format(lisUnableToStreamT, [AnUnitInfo.ComponentName,
|
|
AnUnitInfo.ComponentName]) + LineEnding
|
|
+E.Message;
|
|
if PropPath<>'' then
|
|
AText := Atext + LineEnding + LineEnding + lisPathToInstance
|
|
+ LineEnding + PropPath;
|
|
Result:=MessageDlg(ACaption, AText, mtError,
|
|
[mbAbort, mbRetry, mbIgnore], 0);
|
|
if Result=mrAbort then exit;
|
|
if Result=mrIgnore then Result:=mrOk;
|
|
ComponentSavingOk:=false;
|
|
end;
|
|
end;
|
|
until Result<>mrRetry;
|
|
|
|
// create lazarus form resource code
|
|
if ComponentSavingOk and (LRSFilename<>'') then begin
|
|
if ResourceCode=nil then begin
|
|
ResourceCode:=CodeToolBoss.CreateFile(LRSFilename);
|
|
ComponentSavingOk:=(ResourceCode<>nil);
|
|
end;
|
|
if ComponentSavingOk then begin
|
|
// there is no bug in the source, so the resource code should be
|
|
// changed too
|
|
MemStream:=TExtMemoryStream.Create;
|
|
if AnUnitInfo.ComponentLastLRSStreamSize>0 then
|
|
MemStream.Capacity:=AnUnitInfo.ComponentLastLRSStreamSize+LRSStreamChunkSize;
|
|
try
|
|
BinCompStream.Position:=0;
|
|
BinaryToLazarusResourceCode(BinCompStream,MemStream
|
|
,'T'+AnUnitInfo.ComponentName,'FORMDATA');
|
|
AnUnitInfo.ComponentLastLRSStreamSize:=MemStream.Size;
|
|
MemStream.Position:=0;
|
|
SetLength(CompResourceCode,MemStream.Size);
|
|
MemStream.Read(CompResourceCode[1],length(CompResourceCode));
|
|
finally
|
|
MemStream.Free;
|
|
end;
|
|
end;
|
|
if ComponentSavingOk then begin
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TMainIDE.SaveFileResources E ',CompResourceCode);
|
|
{$ENDIF}
|
|
// replace lazarus form resource code in include file (.lrs)
|
|
if not (sfSaveToTestDir in Flags) then begin
|
|
// if resource name has changed, delete old resource
|
|
if (AnUnitInfo.ComponentName<>AnUnitInfo.ComponentResourceName)
|
|
and (AnUnitInfo.ComponentResourceName<>'') then begin
|
|
CodeToolBoss.RemoveLazarusResource(ResourceCode,
|
|
'T'+AnUnitInfo.ComponentResourceName);
|
|
end;
|
|
// add comment to resource file (if not already exists)
|
|
if (not CodeToolBoss.AddLazarusResourceHeaderComment(ResourceCode,
|
|
LRSComment)) then
|
|
begin
|
|
ACaption:=lisResourceSaveError;
|
|
AText:=Format(lisUnableToAddResourceHeaderCommentToResourceFile, [
|
|
#13, '"', ResourceCode.FileName, '"', #13]);
|
|
Result:=MessageDlg(ACaption,AText,mtError,[mbIgnore,mbAbort],0);
|
|
if Result<>mrIgnore then exit;
|
|
end;
|
|
// add resource to resource file
|
|
if (not CodeToolBoss.AddLazarusResource(ResourceCode,
|
|
'T'+AnUnitInfo.ComponentName,CompResourceCode)) then
|
|
begin
|
|
ACaption:=lisResourceSaveError;
|
|
AText:=Format(
|
|
lisUnableToAddResourceTFORMDATAToResourceFileProbably, [
|
|
AnUnitInfo.ComponentName,
|
|
#13, '"', ResourceCode.FileName, '"', #13]
|
|
);
|
|
Result:=MessageDlg(ACaption, AText, mtError, [mbIgnore, mbAbort],0);
|
|
if Result<>mrIgnore then exit;
|
|
end else begin
|
|
AnUnitInfo.ComponentResourceName:=AnUnitInfo.ComponentName;
|
|
end;
|
|
end else begin
|
|
ResourceCode.Source:=CompResourceCode;
|
|
end;
|
|
end;
|
|
end;
|
|
if ComponentSavingOk then begin
|
|
if (not AnUnitInfo.IsVirtual) or (sfSaveToTestDir in Flags) then
|
|
begin
|
|
// save lfm file
|
|
LFMFilename:=ChangeFileExt(AnUnitInfo.Filename,'.lfm');
|
|
if AnUnitInfo.IsVirtual then
|
|
LFMFilename:=AppendPathDelim(GetTestBuildDirectory)+LFMFilename;
|
|
if LFMCode=nil then begin
|
|
LFMCode:=CodeToolBoss.CreateFile(LFMFilename);
|
|
if LFMCode=nil then begin
|
|
Result:=QuestionDlg(lisUnableToCreateFile,
|
|
Format(lisUnableToCreateFile2, ['"', LFMFilename, '"']),
|
|
mtWarning, [mrIgnore, lisContinueWithoutLoadingForm,
|
|
mrCancel, lisCancelLoadingUnit,
|
|
mrAbort, lisAbortAllLoading], 0);
|
|
if Result<>mrIgnore then exit;
|
|
end;
|
|
end;
|
|
if (LFMCode<>nil) then begin
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TMainIDE.SaveFileResources E2 LFM=',LFMCode.Filename);
|
|
{$ENDIF}
|
|
if (ResType=rtRes) and (LFMCode.DiskEncoding<>EncodingUTF8) then
|
|
begin
|
|
// the .lfm file is used by fpcres, which only supports UTF8 without BOM
|
|
DebugLn(['TMainIDE.DoSaveUnitComponent fixing encoding of ',LFMCode.Filename,' from ',LFMCode.DiskEncoding,' to ',EncodingUTF8]);
|
|
LFMCode.DiskEncoding:=EncodingUTF8;
|
|
end;
|
|
|
|
Result:=mrOk;
|
|
repeat
|
|
try
|
|
// transform binary to text
|
|
TxtCompStream:=TExtMemoryStream.Create;
|
|
if AnUnitInfo.ComponentLastLFMStreamSize>0 then
|
|
TxtCompStream.Capacity:=AnUnitInfo.ComponentLastLFMStreamSize
|
|
+LRSStreamChunkSize;
|
|
try
|
|
BinCompStream.Position:=0;
|
|
LRSObjectBinaryToText(BinCompStream,TxtCompStream);
|
|
AnUnitInfo.ComponentLastLFMStreamSize:=TxtCompStream.Size;
|
|
// stream text to file
|
|
TxtCompStream.Position:=0;
|
|
LFMCode.LoadFromStream(TxtCompStream);
|
|
Result:=SaveCodeBufferToFile(LFMCode,LFMCode.Filename,true);
|
|
if not Result=mrOk then exit;
|
|
Result:=mrCancel;
|
|
finally
|
|
TxtCompStream.Free;
|
|
end;
|
|
except
|
|
on E: Exception do begin
|
|
// added to get more feedback on issue 7009
|
|
Debugln('TMainIDE.SaveFileResources E3: ', E.Message);
|
|
DumpExceptionBackTrace;
|
|
ACaption:=lisStreamingError;
|
|
AText:=Format(
|
|
lisUnableToTransformBinaryComponentStreamOfTIntoText, [
|
|
AnUnitInfo.ComponentName, AnUnitInfo.ComponentName])
|
|
+#13+E.Message;
|
|
Result:=MessageDlg(ACaption, AText, mtError,
|
|
[mbAbort, mbRetry, mbIgnore], 0);
|
|
if Result=mrAbort then exit;
|
|
if Result=mrIgnore then Result:=mrOk;
|
|
end;
|
|
end;
|
|
until Result<>mrRetry;
|
|
end;
|
|
end;
|
|
end;
|
|
// Now the most important file (.lfm) is saved.
|
|
// Now save the secondary files
|
|
|
|
// save the .lrt file containing the list of all translatable strings of
|
|
// the component
|
|
if ComponentSavingOk
|
|
and (Grubber<>nil) and (Grubber.Grubbed.Count>0)
|
|
and (not (sfSaveToTestDir in Flags))
|
|
and (not AnUnitInfo.IsVirtual) then begin
|
|
LRTFilename:=ChangeFileExt(AnUnitInfo.Filename,'.lrt');
|
|
DebugLn(['TMainIDE.DoSaveUnitComponent save lrt: ',LRTFilename]);
|
|
Result:=SaveStringToFile(LRTFilename,Grubber.Grubbed.Text,
|
|
[mbIgnore,mbAbort],AnUnitInfo.Filename);
|
|
if (Result<>mrOk) and (Result<>mrIgnore) then exit;
|
|
end;
|
|
|
|
finally
|
|
try
|
|
FreeAndNil(BinCompStream);
|
|
if DestroyDriver and (Writer<>nil) then Writer.Driver.Free;
|
|
FreeAndNil(Writer);
|
|
FreeAndNil(Grubber);
|
|
FreeAndNil(UnitOwners);
|
|
except
|
|
on E: Exception do begin
|
|
debugln('TMainIDE.SaveFileResources Error cleaning up: ',E.Message);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF IDE_DEBUG}
|
|
if ResourceCode<>nil then
|
|
writeln('TMainIDE.SaveFileResources F ',ResourceCode.Modified);
|
|
{$ENDIF}
|
|
// save binary stream (.lrs)
|
|
if ResourceCode<>nil then begin
|
|
if (not (sfSaveToTestDir in Flags)) then
|
|
begin
|
|
if (ResourceCode.Modified) then begin
|
|
if FilenameIsAbsolute(ResourceCode.Filename) then
|
|
LRSFilename:=ResourceCode.Filename
|
|
else if LRSFilename='' then
|
|
LRSFilename:=MainBuildBoss.FindLRSFilename(AnUnitInfo,true);
|
|
Result:=ForceDirectoryInteractive(ExtractFilePath(LRSFilename),[mbRetry]);
|
|
if not Result=mrOk then exit;
|
|
Result:=SaveCodeBufferToFile(ResourceCode,LRSFilename);
|
|
if not Result=mrOk then exit;
|
|
end;
|
|
end else begin
|
|
TestFilename:=MainBuildBoss.GetTestUnitFilename(AnUnitInfo);
|
|
Result:=SaveCodeBufferToFile(ResourceCode,
|
|
ChangeFileExt(TestFilename,
|
|
ExtractFileExt(ResourceCode.Filename)));
|
|
if not Result=mrOk then exit;
|
|
end;
|
|
end;
|
|
// mark designer unmodified
|
|
ADesigner:=FindRootDesigner(AnUnitInfo.Component) as TDesigner;
|
|
if ADesigner<>nil then
|
|
ADesigner.DefaultFormBoundsValid:=false;
|
|
|
|
Result:=mrOk;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TMainIDE.SaveFileResources G ',LFMCode<>nil);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TMainIDE.DoRemoveDanglingEvents(AnUnitInfo: TUnitInfo;
|
|
OkOnCodeErrors: boolean): TModalResult;
|
|
var
|
|
ComponentModified: boolean;
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
begin
|
|
Result:=mrOk;
|
|
if (AnUnitInfo.Component=nil) then exit;
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
// unselect methods in ObjectInspector1
|
|
if (ObjectInspector1.PropertyEditorHook.LookupRoot=AnUnitInfo.Component) then
|
|
begin
|
|
ObjectInspector1.EventGrid.ItemIndex:=-1;
|
|
ObjectInspector1.FavouriteGrid.ItemIndex:=-1;
|
|
end;
|
|
//debugln('TMainIDE.DoRemoveDanglingEvents ',AnUnitInfo.Filename,' ',dbgsName(AnUnitInfo.Component));
|
|
// remove dangling methods
|
|
Result:=RemoveDanglingEvents(AnUnitInfo.Component,AnUnitInfo.Source,true,
|
|
ComponentModified);
|
|
// update ObjectInspector1
|
|
if ComponentModified
|
|
and (ObjectInspector1.PropertyEditorHook.LookupRoot=AnUnitInfo.Component) then
|
|
begin
|
|
ObjectInspector1.EventGrid.RefreshPropertyValues;
|
|
ObjectInspector1.FavouriteGrid.RefreshPropertyValues;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoRenameUnit(AnUnitInfo: TUnitInfo;
|
|
NewFilename, NewUnitName: string;
|
|
var ResourceCode: TCodeBuffer): TModalresult;
|
|
var
|
|
NewLFMFilename: String;
|
|
OldSourceCode: String;
|
|
NewSource: TCodeBuffer;
|
|
NewFilePath: String;
|
|
NewResFilePath: String;
|
|
OldFilePath: String;
|
|
OldResFilePath: String;
|
|
OldFilename: String;
|
|
NewResFilename: String;
|
|
NewHighlighter: TLazSyntaxHighlighter;
|
|
AmbiguousFiles: TStringList;
|
|
AmbiguousText: string;
|
|
i: Integer;
|
|
AmbiguousFilename: String;
|
|
OldUnitPath: String;
|
|
OldLFMFilename: String;
|
|
OldLRSFilename: String;
|
|
OldPPUFilename: String;
|
|
OutDir: string;
|
|
Owners: TFPList;
|
|
LFMBuf: TCodeBuffer;
|
|
begin
|
|
Project1.BeginUpdate(false);
|
|
try
|
|
OldFilename:=AnUnitInfo.Filename;
|
|
OldFilePath:=ExtractFilePath(OldFilename);
|
|
OldLFMFilename:=ChangeFileExt(OldFilename,'.lfm');
|
|
if not FileExistsUTF8(OldLFMFilename) then
|
|
OldLFMFilename:=ChangeFileExt(OldFilename,'.dfm');
|
|
if NewUnitName='' then
|
|
NewUnitName:=AnUnitInfo.Unit_Name;
|
|
debugln(['TMainIDE.DoRenameUnit ',AnUnitInfo.Filename,' NewUnitName=',NewUnitName,' OldUnitName=',AnUnitInfo.Unit_Name,' ResourceCode=',ResourceCode<>nil,' NewFilename="',NewFilename,'"']);
|
|
|
|
// check new resource file
|
|
NewLFMFilename:=ChangeFileExt(NewFilename,'.lfm');
|
|
if AnUnitInfo.ComponentName='' then begin
|
|
// unit has no component
|
|
// -> remove lfm file, so that it will not be auto loaded on next open
|
|
if (FileExistsUTF8(NewLFMFilename))
|
|
and (not DeleteFileUTF8(NewLFMFilename))
|
|
and (MessageDlg(lisPkgMangDeleteFailed, Format(lisDeletingOfFileFailed, [
|
|
'"', NewLFMFilename, '"']), mtError, [mbIgnore, mbCancel], 0)=mrCancel)
|
|
then
|
|
begin
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
// create new source with the new filename
|
|
OldSourceCode:=AnUnitInfo.Source.Source;
|
|
NewSource:=CodeToolBoss.CreateFile(NewFilename);
|
|
NewSource.Source:=OldSourceCode;
|
|
if NewSource=nil then begin
|
|
Result:=MessageDlg(lisUnableToCreateFile,
|
|
Format(lisCanNotCreateFile, ['"', NewFilename, '"']),
|
|
mtError,[mbCancel,mbAbort],0);
|
|
exit;
|
|
end;
|
|
// get final filename
|
|
NewFilename:=NewSource.Filename;
|
|
NewFilePath:=ExtractFilePath(NewFilename);
|
|
EnvironmentOptions.RemoveFromRecentOpenFiles(OldFilename);
|
|
EnvironmentOptions.AddToRecentOpenFiles(NewFilename);
|
|
SetRecentFilesMenu;
|
|
|
|
// add new path to unit path
|
|
if AnUnitInfo.IsPartOfProject
|
|
and (not Project1.IsVirtual)
|
|
and (FilenameIsPascalUnit(NewFilename))
|
|
and (CompareFilenames(NewFilePath,Project1.ProjectDirectory)<>0) then begin
|
|
OldUnitPath:=Project1.CompilerOptions.GetUnitPath(false);
|
|
|
|
if SearchDirectoryInSearchPath(OldUnitPath,NewFilePath,1)<1 then begin
|
|
//DebugLn('TMainIDE.DoRenameUnit NewFilePath="',NewFilePath,'" OldUnitPath="',OldUnitPath,'"');
|
|
if MessageDlg(lisExtendUnitPath,
|
|
Format(lisTheDirectoryIsNotYetInTheUnitPathAddIt, ['"', NewFilePath,
|
|
'"', #13]),
|
|
mtConfirmation,[mbYes,mbNo],0)=mrYes then
|
|
begin
|
|
Project1.CompilerOptions.OtherUnitFiles:=
|
|
Project1.CompilerOptions.OtherUnitFiles+';'
|
|
+CreateRelativePath(NewFilePath,Project1.ProjectDirectory);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// rename Resource file (.lrs)
|
|
if (ResourceCode<>nil) then begin
|
|
// the resource include line in the code will be changed later after
|
|
// changing the unitname
|
|
if AnUnitInfo.IsPartOfProject
|
|
and (not Project1.IsVirtual)
|
|
and (pfLRSFilesInOutputDirectory in Project1.Flags) then begin
|
|
NewResFilename:=MainBuildBoss.GetDefaultLRSFilename(AnUnitInfo);
|
|
NewResFilename:=AppendPathDelim(ExtractFilePath(NewResFilename))
|
|
+ExtractFileNameOnly(NewFilename)+ResourceFileExt;
|
|
end else begin
|
|
OldResFilePath:=ExtractFilePath(ResourceCode.Filename);
|
|
NewResFilePath:=OldResFilePath;
|
|
if FilenameIsAbsolute(OldFilePath)
|
|
and FileIsInPath(OldResFilePath,OldFilePath) then begin
|
|
// resource code was in the same or in a sub directory of source
|
|
// -> try to keep this relationship
|
|
NewResFilePath:=NewFilePath
|
|
+copy(ResourceCode.Filename,length(OldFilePath)+1,
|
|
length(ResourceCode.Filename));
|
|
if not DirPathExists(NewResFilePath) then
|
|
NewResFilePath:=NewFilePath;
|
|
end else begin
|
|
// resource code was not in the same or in a sub directory of source
|
|
// copy resource into the same directory as the source
|
|
NewResFilePath:=NewFilePath;
|
|
end;
|
|
NewResFilename:=NewResFilePath
|
|
+ExtractFileNameOnly(NewFilename)+ResourceFileExt;
|
|
end;
|
|
Result:=ForceDirectoryInteractive(ExtractFilePath(NewResFilename),[mbRetry,mbIgnore]);
|
|
if Result=mrCancel then exit;
|
|
if Result=mrOk then begin
|
|
if not CodeToolBoss.SaveBufferAs(ResourceCode,NewResFilename,ResourceCode)
|
|
then
|
|
DebugLn(['TMainIDE.DoRenameUnit CodeToolBoss.SaveBufferAs failed: NewResFilename="',NewResFilename,'"']);
|
|
end;
|
|
|
|
{$IFDEF IDE_DEBUG}
|
|
debugln(['TMainIDE.DoRenameUnit C ',ResourceCode<>nil]);
|
|
debugln([' NewResFilePath="',NewResFilePath,'" NewResFilename="',NewResFilename,'"']);
|
|
if ResourceCode<>nil then debugln('*** ResourceFileName ',ResourceCode.Filename);
|
|
{$ENDIF}
|
|
end else begin
|
|
NewResFilename:='';
|
|
end;
|
|
// rename unit name of jit class
|
|
if (AnUnitInfo.Component<>nil) then
|
|
FormEditor1.RenameJITComponentUnitname(AnUnitInfo.Component,NewUnitName);
|
|
{$IFDEF IDE_DEBUG}
|
|
if AnUnitInfo.Component<>nil then debugln('*** AnUnitInfo.Component ',dbgsName(AnUnitInfo.Component),' ClassUnitname=',GetClassUnitName(AnUnitInfo.Component.ClassType));
|
|
debugln(['TMainIDE.DoRenameUnit D ',ResourceCode<>nil]);
|
|
{$ENDIF}
|
|
|
|
// save new lfm
|
|
if FilenameIsAbsolute(OldLFMFilename) and FileExistsUTF8(OldLFMFilename) then
|
|
begin
|
|
LFMBuf:=CodeToolBoss.LoadFile(OldLFMFilename,false,false);
|
|
if (LFMBuf<>nil) and FilenameIsAbsolute(NewLFMFilename) then begin
|
|
Result:=SaveCodeBufferToFile(LFMBuf,NewLFMFilename,true);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TMainIDE.DoRenameUnit SaveCodeBufferToFile failed for ',NewLFMFilename]);
|
|
end;
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
end;
|
|
|
|
// set new codebuffer in unitinfo and sourceeditor
|
|
AnUnitInfo.Source:=NewSource;
|
|
AnUnitInfo.ClearModifieds;
|
|
for i := 0 to AnUnitInfo.EditorInfoCount -1 do
|
|
if AnUnitInfo.EditorInfo[i].EditorComponent <> nil then
|
|
TSourceEditor(AnUnitInfo.EditorInfo[i].EditorComponent).CodeBuffer := NewSource;
|
|
// the code is not changed, therefore the marks are kept
|
|
|
|
// change unitname in lpi and in main source file
|
|
AnUnitInfo.Unit_Name:=NewUnitName;
|
|
if ResourceCode<>nil then begin
|
|
// change resource filename in the source include directive
|
|
if not CodeToolBoss.RenameMainInclude(AnUnitInfo.Source,
|
|
ExtractFilename(ResourceCode.Filename),false)
|
|
then
|
|
DebugLn(['TMainIDE.DoRenameUnit CodeToolBoss.RenameMainInclude failed: AnUnitInfo.Source="',AnUnitInfo.Source,'" ResourceCode="',ExtractFilename(ResourceCode.Filename),'"']);
|
|
end;
|
|
|
|
// change unitname on SourceNotebook
|
|
if AnUnitInfo.OpenEditorInfoCount > 0 then
|
|
UpdateSourceNames;
|
|
|
|
// change syntax highlighter
|
|
NewHighlighter:=FilenameToLazSyntaxHighlighter(NewFilename);
|
|
AnUnitInfo.UpdateDefaultHighlighter(NewHighlighter);
|
|
for i := 0 to AnUnitInfo.EditorInfoCount - 1 do
|
|
if (AnUnitInfo.EditorInfo[i].EditorComponent <> nil) and
|
|
(not AnUnitInfo.EditorInfo[i].CustomHighlighter)
|
|
then
|
|
TSourceEditor(AnUnitInfo.EditorInfo[i].EditorComponent).SyntaxHighlighterType :=
|
|
AnUnitInfo.EditorInfo[i].SyntaxHighlighter;
|
|
|
|
// save file
|
|
if not NewSource.IsVirtual then begin
|
|
Result:=AnUnitInfo.WriteUnitSource;
|
|
if Result<>mrOk then exit;
|
|
AnUnitInfo.Modified:=false;
|
|
end;
|
|
|
|
// change lpks containing the file
|
|
Result:=PkgBoss.OnRenameFile(OldFilename,AnUnitInfo.Filename,
|
|
AnUnitInfo.IsPartOfProject);
|
|
if Result=mrAbort then exit;
|
|
|
|
// delete ambiguous files
|
|
NewFilePath:=ExtractFilePath(NewFilename);
|
|
AmbiguousFiles:=
|
|
FindFilesCaseInsensitive(NewFilePath,ExtractFilename(NewFilename),true);
|
|
if AmbiguousFiles<>nil then begin
|
|
try
|
|
if (AmbiguousFiles.Count=1)
|
|
and (CompareFilenames(OldFilePath,NewFilePath)=0)
|
|
and (CompareFilenames(AmbiguousFiles[0],ExtractFilename(OldFilename))=0)
|
|
then
|
|
AmbiguousText:=Format(lisDeleteOldFile, ['"', ExtractFilename(
|
|
OldFilename), '"'])
|
|
else
|
|
AmbiguousText:=
|
|
Format(lisThereAreOtherFilesInTheDirectoryWithTheSameName,
|
|
[#13, #13, AmbiguousFiles.Text, #13]);
|
|
Result:=MessageDlg(lisAmbiguousFilesFound, AmbiguousText,
|
|
mtWarning,[mbYes,mbNo,mbAbort],0);
|
|
if Result=mrAbort then exit;
|
|
if Result=mrYes then begin
|
|
NewFilePath:=AppendPathDelim(ExtractFilePath(NewFilename));
|
|
for i:=0 to AmbiguousFiles.Count-1 do begin
|
|
AmbiguousFilename:=NewFilePath+AmbiguousFiles[i];
|
|
if (FileExistsUTF8(AmbiguousFilename))
|
|
and (not DeleteFileUTF8(AmbiguousFilename))
|
|
and (MessageDlg(lisPkgMangDeleteFailed, Format(lisDeletingOfFileFailed,
|
|
['"', AmbiguousFilename, '"']), mtError, [mbIgnore, mbCancel], 0)=
|
|
mrCancel) then
|
|
begin
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
AmbiguousFiles.Free;
|
|
end;
|
|
end;
|
|
|
|
// remove old path from unit path
|
|
if AnUnitInfo.IsPartOfProject
|
|
and (FilenameIsPascalUnit(OldFilename))
|
|
and (OldFilePath<>'') then begin
|
|
//DebugLn('TMainIDE.DoRenameUnit OldFilePath="',OldFilePath,'" SourceDirs="',Project1.SourceDirectories.CreateSearchPathFromAllFiles,'"');
|
|
if (SearchDirectoryInSearchPath(
|
|
Project1.SourceDirectories.CreateSearchPathFromAllFiles,OldFilePath,1)<1)
|
|
then begin
|
|
//DebugLn('TMainIDE.DoRenameUnit OldFilePath="',OldFilePath,'" UnitPath="',Project1.CompilerOptions.GetUnitPath(false),'"');
|
|
if (SearchDirectoryInSearchPath(
|
|
Project1.CompilerOptions.GetUnitPath(false),OldFilePath,1)<1)
|
|
then begin
|
|
if MessageDlg(lisCleanUpUnitPath,
|
|
Format(lisTheDirectoryIsNoLongerNeededInTheUnitPathRemoveIt, ['"',
|
|
OldFilePath, '"', #13]),
|
|
mtConfirmation,[mbYes,mbNo],0)=mrYes then
|
|
begin
|
|
Project1.CompilerOptions.OtherUnitFiles:=
|
|
RemoveSearchPaths(Project1.CompilerOptions.OtherUnitFiles,
|
|
OldUnitPath);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// delete old pas, .pp, .ppu
|
|
if (CompareFilenames(NewFilename,OldFilename)<>0)
|
|
and FilenameIsAbsolute(OldFilename) and FileExistsUTF8(OldFilename) then begin
|
|
if MessageDlg(lisDeleteOldFile2,
|
|
Format(lisDeleteOldFile, ['"', OldFilename, '"']),
|
|
mtConfirmation,[mbYes,mbNo],0)=mrYes then
|
|
begin
|
|
Result:=DeleteFileInteractive(OldFilename,[mbAbort]);
|
|
if Result=mrAbort then exit;
|
|
// delete old lfm
|
|
if FileExistsUTF8(NewLFMFilename) then begin
|
|
// the new file has a lfm, so it is safe to delete the old
|
|
// (if NewLFMFilename does not exist, it didn't belong to the unit
|
|
// or there was an error during delete. Never delete files in doubt.)
|
|
OldLFMFilename:=ChangeFileExt(OldFilename,'.lfm');
|
|
if FileExistsUTF8(OldLFMFilename) then begin
|
|
Result:=DeleteFileInteractive(OldLFMFilename,[mbAbort]);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
end;
|
|
// delete old lrs
|
|
if (ResourceCode<>nil) and FileExistsUTF8(ResourceCode.Filename) then begin
|
|
// the new file has a lrs, so it is safe to delete the old
|
|
// (if the new lrs does not exist, it didn't belong to the unit
|
|
// or there was an error during delete. Never delete files in doubt.)
|
|
OldLRSFilename:=ChangeFileExt(OldFilename,ResourceFileExt);
|
|
if FileExistsUTF8(OldLRSFilename) then begin
|
|
Result:=DeleteFileInteractive(OldLRSFilename,[mbAbort]);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
end;
|
|
// delete ppu in source directory
|
|
OldPPUFilename:=ChangeFileExt(OldFilename,'.ppu');
|
|
if FileExistsUTF8(OldPPUFilename) then begin
|
|
Result:=DeleteFileInteractive(OldPPUFilename,[mbAbort]);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
OldPPUFilename:=ChangeFileExt(OldPPUFilename,'.o');
|
|
if FileExistsUTF8(OldPPUFilename) then begin
|
|
Result:=DeleteFileInteractive(OldPPUFilename,[mbAbort]);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
Owners:=PkgBoss.GetOwnersOfUnit(NewFilename);
|
|
try
|
|
if Owners<>nil then begin
|
|
for i:=0 to Owners.Count-1 do begin
|
|
OutDir:='';
|
|
if TObject(Owners[i]) is TProject then begin
|
|
// delete old files in project output directory
|
|
OutDir:=TProject(Owners[i]).CompilerOptions.GetUnitOutPath(false);
|
|
end else if TObject(Owners[i]) is TLazPackage then begin
|
|
// delete old files in package output directory
|
|
OutDir:=TLazPackage(Owners[i]).CompilerOptions.GetUnitOutPath(false);
|
|
end;
|
|
if (OutDir<>'') and FilenameIsAbsolute(OutDir) then begin
|
|
OldPPUFilename:=AppendPathDelim(OutDir)+ChangeFileExt(ExtractFilenameOnly(OldFilename),'.ppu');
|
|
if FileExistsUTF8(OldPPUFilename) then begin
|
|
Result:=DeleteFileInteractive(OldPPUFilename,[mbAbort]);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
OldPPUFilename:=ChangeFileExt(OldPPUFilename,'.o');
|
|
if FileExistsUTF8(OldPPUFilename) then begin
|
|
Result:=DeleteFileInteractive(OldPPUFilename,[mbAbort]);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
OldLRSFilename:=ChangeFileExt(OldPPUFilename,ResourceFileExt);
|
|
if FileExistsUTF8(OldLRSFilename) then begin
|
|
Result:=DeleteFileInteractive(OldLRSFilename,[mbAbort]);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
Owners.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
finally
|
|
Project1.EndUpdate;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoOpenNotExistingFile(const AFileName: string;
|
|
Flags: TOpenFlags): TModalResult;
|
|
var
|
|
NewFlags: TNewFlags;
|
|
begin
|
|
if ofProjectLoading in Flags then begin
|
|
// this is a file, that was loaded last time, but was removed from disk
|
|
Result:=QuestionDlg(lisFileNotFound,
|
|
Format(lisTheFileWasNotFoundIgnoreWillGoOnLoadingTheProject, ['"',
|
|
AFilename, '"', #13, #13, #13]),
|
|
mtError, [mrIgnore, lisSkipFileAndContinueLoading,
|
|
mrAbort, lisAbortLoadingProject],
|
|
0);
|
|
exit;
|
|
end;
|
|
|
|
// Default to cancel
|
|
Result:=mrCancel;
|
|
if ofQuiet in Flags then Exit;
|
|
|
|
if ofOnlyIfExists in Flags
|
|
then begin
|
|
MessageDlg(lisFileNotFound, Format(lisFileNotFound2, ['"', AFilename, '"',
|
|
#13]),
|
|
mtInformation,[mbCancel],0);
|
|
// cancel loading file
|
|
Exit;
|
|
end;
|
|
|
|
if MessageDlg(lisFileNotFound,
|
|
Format(lisFileNotFoundDoYouWantToCreateIt, ['"', AFilename, '"', #13, #13])
|
|
,mtInformation,[mbYes,mbNo],0)=mrYes then
|
|
begin
|
|
// create new file
|
|
NewFlags:=[nfOpenInEditor,nfCreateDefaultSrc];
|
|
if ofAddToProject in Flags then
|
|
Include(NewFlags,nfIsPartOfProject);
|
|
if FilenameIsPascalSource(AFilename) then
|
|
Result:=DoNewEditorFile(FileDescriptorUnit,AFilename,'',NewFlags)
|
|
else
|
|
Result:=DoNewEditorFile(FileDescriptorText,AFilename,'',NewFlags);
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoOpenUnknownFile(const AFileName: string; Flags: TOpenFlags;
|
|
var NewUnitInfo: TUnitInfo; var Handled: boolean): TModalResult;
|
|
var
|
|
Ext, NewProgramName, LPIFilename, ACaption, AText: string;
|
|
PreReadBuf: TCodeBuffer;
|
|
LoadFlags: TLoadBufferFlags;
|
|
SourceType: String;
|
|
begin
|
|
Handled:=false;
|
|
Ext:=lowercase(ExtractFileExt(AFilename));
|
|
|
|
if ([ofProjectLoading,ofRegularFile]*Flags=[]) and (ToolStatus=itNone)
|
|
and (Ext='.lpi') then begin
|
|
// this is a project info file -> load whole project
|
|
Result:=DoOpenProjectFile(AFilename,[ofAddToRecent]);
|
|
Handled:=true;
|
|
exit;
|
|
end;
|
|
|
|
// load the source
|
|
LoadFlags := [lbfCheckIfText,lbfUpdateFromDisk,lbfRevert];
|
|
if ofQuiet in Flags then Include(LoadFlags, lbfQuiet);
|
|
Result:=LoadCodeBuffer(PreReadBuf,AFileName,LoadFlags,true);
|
|
if Result<>mrOk then exit;
|
|
NewUnitInfo:=nil;
|
|
|
|
// check if unit is a program
|
|
if ([ofProjectLoading,ofRegularFile]*Flags=[])
|
|
and FilenameIsPascalSource(AFilename) then begin
|
|
SourceType:=CodeToolBoss.GetSourceType(PreReadBuf,false);
|
|
if (SysUtils.CompareText(SourceType,'PROGRAM')=0)
|
|
or (SysUtils.CompareText(SourceType,'LIBRARY')=0)
|
|
then begin
|
|
NewProgramName:=CodeToolBoss.GetSourceName(PreReadBuf,false);
|
|
if NewProgramName<>'' then begin
|
|
// source is a program
|
|
// either this is a lazarus project
|
|
// or it is not yet a lazarus project ;)
|
|
LPIFilename:=ChangeFileExt(AFilename,'.lpi');
|
|
if FileExistsUTF8(LPIFilename) then begin
|
|
if QuestionDlg(lisProjectInfoFileDetected,
|
|
Format(lisTheFileSeemsToBeTheProgramFileOfAnExistingLazarusP, [
|
|
AFilename]), mtConfirmation,
|
|
[mrOk, lisOpenProject2, mrCancel, lisOpenTheFileAsNormalSource], 0)
|
|
=mrOk then
|
|
begin
|
|
Result:=DoOpenProjectFile(LPIFilename,[]);
|
|
Handled:=true;
|
|
exit;
|
|
end;
|
|
end else begin
|
|
AText:=Format(lisTheFileSeemsToBeAProgramCloseCurrentProject, ['"',
|
|
AFilename, '"', #13, #13]);
|
|
ACaption:=lisProgramDetected;
|
|
if MessageDlg(ACaption, AText, mtConfirmation,
|
|
[mbYes, mbNo], 0)=mrYes then
|
|
begin
|
|
Result:=DoCreateProjectForProgram(PreReadBuf);
|
|
Handled:=true;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
NewUnitInfo:=TUnitInfo.Create(PreReadBuf);
|
|
if FilenameIsPascalSource(NewUnitInfo.Filename) then
|
|
NewUnitInfo.ReadUnitNameFromSource(true);
|
|
Project1.AddFile(NewUnitInfo,false);
|
|
if (ofAddToProject in Flags) and (not NewUnitInfo.IsPartOfProject) then
|
|
begin
|
|
NewUnitInfo.IsPartOfProject:=true;
|
|
Project1.Modified:=true;
|
|
end;
|
|
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoLoadLFM(AnUnitInfo: TUnitInfo;
|
|
OpenFlags: TOpenFlags; CloseFlags: TCloseFlags): TModalResult;
|
|
// if there is a .lfm file, open the resource
|
|
var
|
|
LFMFilename: string;
|
|
LFMBuf: TCodeBuffer;
|
|
CanAbort: boolean;
|
|
begin
|
|
CanAbort:=[ofProjectLoading,ofMultiOpen]*OpenFlags<>[];
|
|
|
|
// Note: think about virtual and normal .lfm files.
|
|
LFMFilename:=ChangeFileExt(AnUnitInfo.Filename,'.lfm');
|
|
if not FileExistsInIDE(LFMFilename,[pfsfOnlyEditorFiles]) then
|
|
LFMFilename:=ChangeFileExt(AnUnitInfo.Filename,'.dfm');
|
|
LFMBuf:=nil;
|
|
if not FileExistsInIDE(LFMFilename,[pfsfOnlyEditorFiles]) then begin
|
|
// there is no LFM file -> ok
|
|
{$IFDEF IDE_DEBUG}
|
|
debugln('TMainIDE.DoLoadLFM there is no LFM file for "',AnUnitInfo.Filename,'"');
|
|
{$ENDIF}
|
|
Result:=mrOk;
|
|
exit;
|
|
end;
|
|
|
|
// there is a lazarus form text file -> load it
|
|
Result:=LoadIDECodeBuffer(LFMBuf,LFMFilename,[lbfUpdateFromDisk],CanAbort);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TMainIDE.DoLoadLFM LoadIDECodeBuffer failed']);
|
|
exit;
|
|
end;
|
|
|
|
Result:=DoLoadLFM(AnUnitInfo,LFMBuf,OpenFlags,CloseFlags);
|
|
end;
|
|
|
|
function TMainIDE.DoLoadLFM(AnUnitInfo: TUnitInfo; LFMBuf: TCodeBuffer;
|
|
OpenFlags: TOpenFlags; CloseFlags: TCloseFlags): TModalResult;
|
|
const
|
|
BufSize = 4096; // allocating mem in 4k chunks helps many mem managers
|
|
|
|
ShowCommands: array[TWindowState] of Integer =
|
|
(SW_SHOWNORMAL, SW_MINIMIZE, SW_SHOWMAXIMIZED, SW_SHOWFULLSCREEN);
|
|
|
|
var
|
|
TxtLFMStream, BinStream: TExtMemoryStream;
|
|
NewComponent: TComponent;
|
|
AncestorType: TComponentClass;
|
|
DesignerForm: TCustomForm;
|
|
NewClassName: String;
|
|
LFMType: String;
|
|
ACaption, AText: String;
|
|
NewUnitName: String;
|
|
AncestorUnitInfo: TUnitInfo;
|
|
ReferencesLocked: Boolean;
|
|
LCLVersion: string;
|
|
MissingClasses: TStrings;
|
|
LFMComponentName: string;
|
|
i: Integer;
|
|
NestedClassName: string;
|
|
NestedClass: TComponentClass;
|
|
NestedUnitInfo: TUnitInfo;
|
|
DisableAutoSize: Boolean;
|
|
NewControl: TControl;
|
|
begin
|
|
{$IFDEF IDE_DEBUG}
|
|
debugln('TMainIDE.DoLoadLFM A ',AnUnitInfo.Filename,' IsPartOfProject=',dbgs(AnUnitInfo.IsPartOfProject),' ');
|
|
{$ENDIF}
|
|
|
|
ReferencesLocked:=false;
|
|
MissingClasses:=nil;
|
|
NewComponent:=nil;
|
|
try
|
|
if (ofRevert in OpenFlags) and (AnUnitInfo.Component<>nil) then begin
|
|
// the component must be destroyed and recreated
|
|
// => store references
|
|
ReferencesLocked:=true;
|
|
Project1.LockUnitComponentDependencies;
|
|
Project1.UpdateUnitComponentDependencies;
|
|
|
|
// close old designer form
|
|
Result:=CloseUnitComponent(AnUnitInfo,CloseFlags);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TMainIDE.DoLoadLFM CloseUnitComponent failed']);
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
// check installed packages
|
|
if EnvironmentOptions.CheckPackagesOnFormCreate and
|
|
(AnUnitInfo.Component = nil) and
|
|
AnUnitInfo.IsPartOfProject and
|
|
(not (ofProjectLoading in OpenFlags)) then
|
|
begin
|
|
// opening a form of the project -> check installed packages
|
|
Result := PkgBoss.CheckProjectHasInstalledPackages(Project1,
|
|
OpenFlags * [ofProjectLoading, ofQuiet] = []);
|
|
if not (Result in [mrOk, mrIgnore]) then
|
|
begin
|
|
DebugLn(['TMainIDE.DoLoadLFM PkgBoss.CheckProjectHasInstalledPackages failed']);
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
//debugln('TMainIDE.DoLoadLFM LFM file loaded, parsing "',LFMBuf.Filename,'" ...');
|
|
|
|
if not AnUnitInfo.HasResources then begin
|
|
// someone created a .lfm file -> Update HasResources
|
|
AnUnitInfo.HasResources:=true;
|
|
end;
|
|
|
|
//debugln('TMainIDE.DoLoadLFM LFM="',LFMBuf.Source,'"');
|
|
|
|
if AnUnitInfo.Component=nil then begin
|
|
// load/create new instance
|
|
|
|
// find the classname of the LFM, and check for inherited form
|
|
QuickCheckLFMBuffer(AnUnitInfo.Source,LFMBuf,LFMType,LFMComponentName,
|
|
NewClassName,LCLVersion,MissingClasses);
|
|
if (NewClassName='') or (LFMType='') then begin
|
|
DebugLn(['TMainIDE.DoLoadLFM LFM file corrupt']);
|
|
Result:=MessageDlg(lisLFMFileCorrupt,
|
|
Format(lisUnableToFindAValidClassnameIn, ['"', LFMBuf.Filename, '"']),
|
|
mtError,[mbIgnore,mbCancel,mbAbort],0);
|
|
exit;
|
|
end;
|
|
|
|
// load missing component classes (e.g. ancestor and frames)
|
|
Result:=DoLoadAncestorDependencyHidden(AnUnitInfo,NewClassName,OpenFlags,
|
|
AncestorType,AncestorUnitInfo);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TMainIDE.DoLoadLFM DoLoadAncestorDependencyHidden failed for ',AnUnitInfo.Filename]);
|
|
exit;
|
|
end;
|
|
|
|
if MissingClasses<>nil then begin
|
|
//DebugLn(['TMainIDE.DoLoadLFM has nested: ',AnUnitInfo.Filename]);
|
|
for i:=MissingClasses.Count-1 downto 0 do begin
|
|
NestedClassName:=MissingClasses[i];
|
|
//DebugLn(['TMainIDE.DoLoadLFM nested ',i,' ',MissingClasses.Count,': ',NestedClassName]);
|
|
if SysUtils.CompareText(NestedClassName,AncestorType.ClassName)=0 then
|
|
begin
|
|
MissingClasses.Delete(i);
|
|
end else begin
|
|
DebugLn(['TMainIDE.DoLoadLFM loading nested class ',NestedClassName,' needed by ',AnUnitInfo.Filename]);
|
|
NestedClass:=nil;
|
|
NestedUnitInfo:=nil;
|
|
Result:=DoLoadComponentDependencyHidden(AnUnitInfo,NestedClassName,
|
|
OpenFlags,true,NestedClass,NestedUnitInfo);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TMainIDE.DoLoadLFM DoLoadComponentDependencyHidden NestedClassName=',NestedClassName,' failed for ',AnUnitInfo.Filename]);
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
//DebugLn(['TMainIDE.DoLoadLFM had nested: ',AnUnitInfo.Filename]);
|
|
end;
|
|
|
|
BinStream:=nil;
|
|
try
|
|
// convert text to binary format
|
|
BinStream:=TExtMemoryStream.Create;
|
|
TxtLFMStream:=TExtMemoryStream.Create;
|
|
try
|
|
{$IFDEF VerboseIDELFMConversion}
|
|
DebugLn(['TMainIDE.DoLoadLFM LFMBuf START =======================================']);
|
|
DebugLn(LFMBuf.Source);
|
|
DebugLn(['TMainIDE.DoLoadLFM LFMBuf END =======================================']);
|
|
{$ENDIF}
|
|
LFMBuf.SaveToStream(TxtLFMStream);
|
|
AnUnitInfo.ComponentLastLFMStreamSize:=TxtLFMStream.Size;
|
|
TxtLFMStream.Position:=0;
|
|
|
|
try
|
|
if AnUnitInfo.ComponentLastBinStreamSize>0 then
|
|
BinStream.Capacity:=AnUnitInfo.ComponentLastBinStreamSize+BufSize;
|
|
LRSObjectTextToBinary(TxtLFMStream,BinStream);
|
|
AnUnitInfo.ComponentLastBinStreamSize:=BinStream.Size;
|
|
BinStream.Position:=0;
|
|
|
|
{$IFDEF VerboseIDELFMConversion}
|
|
DebugLn(['TMainIDE.DoLoadLFM Binary START =======================================']);
|
|
debugln(dbgMemStream(BinStream,BinStream.Size));
|
|
DebugLn(['TMainIDE.DoLoadLFM Binary END =======================================']);
|
|
BinStream.Position:=0;
|
|
{$ENDIF}
|
|
|
|
Result:=mrOk;
|
|
except
|
|
on E: Exception do begin
|
|
DumpExceptionBackTrace;
|
|
ACaption:=lisFormatError;
|
|
AText:=Format(lisUnableToConvertTextFormDataOfFileIntoBinaryStream,
|
|
[#13, '"', LFMBuf.Filename, '"', #13, E.Message]);
|
|
Result:=MessageDlg(ACaption, AText, mtError, [mbOk, mbCancel], 0);
|
|
if Result=mrCancel then Result:=mrAbort;
|
|
exit;
|
|
end;
|
|
end;
|
|
finally
|
|
TxtLFMStream.Free;
|
|
end;
|
|
if ([ofProjectLoading,ofLoadHiddenResource]*OpenFlags=[]) then
|
|
FormEditor1.ClearSelection;
|
|
|
|
// create JIT component
|
|
NewUnitName:=AnUnitInfo.Unit_Name;
|
|
if NewUnitName='' then
|
|
NewUnitName:=ExtractFileNameOnly(AnUnitInfo.Filename);
|
|
// ToDo: create AncestorBinStream(s) via hook, not via parameters
|
|
DisableAutoSize:=true;
|
|
NewComponent:=FormEditor1.CreateRawComponentFromStream(BinStream,
|
|
AncestorType,copy(NewUnitName,1,255),true,true,DisableAutoSize,AnUnitInfo);
|
|
if (NewComponent is TControl) then begin
|
|
NewControl:=TControl(NewComponent);
|
|
if ofLoadHiddenResource in OpenFlags then
|
|
NewControl.ControlStyle:=NewControl.ControlStyle+[csNoDesignVisible];
|
|
if DisableAutoSize then
|
|
NewControl.EnableAutoSizing;
|
|
end;
|
|
Project1.InvalidateUnitComponentDesignerDependencies;
|
|
AnUnitInfo.Component:=NewComponent;
|
|
if (AncestorUnitInfo<>nil) then
|
|
AnUnitInfo.AddRequiresComponentDependency(AncestorUnitInfo,[ucdtAncestor]);
|
|
if NewComponent<>nil then begin
|
|
// component loaded, now load the referenced units
|
|
Result:=DoFixupComponentReferences(AnUnitInfo.Component,OpenFlags);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TMainIDE.DoLoadLFM DoFixupComponentReferences failed']);
|
|
exit;
|
|
end;
|
|
end else begin
|
|
// error streaming component -> examine lfm file
|
|
DebugLn('ERROR: streaming failed lfm="',LFMBuf.Filename,'"');
|
|
// open lfm file in editor
|
|
if AnUnitInfo.OpenEditorInfoCount > 0 then
|
|
Result:=DoOpenEditorFile(LFMBuf.Filename,
|
|
AnUnitInfo.OpenEditorInfo[0].PageIndex+1,
|
|
AnUnitInfo.OpenEditorInfo[0].WindowIndex,
|
|
OpenFlags+[ofOnlyIfExists,ofQuiet,ofRegularFile])
|
|
else
|
|
Result:=DoOpenEditorFile(LFMBuf.Filename, -1, -1,
|
|
OpenFlags+[ofOnlyIfExists,ofQuiet,ofRegularFile]);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TMainIDE.DoLoadLFM DoOpenEditorFile failed']);
|
|
exit;
|
|
end;
|
|
Result:=DoCheckLFMInEditor(true);
|
|
if Result=mrOk then Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
finally
|
|
BinStream.Free;
|
|
end;
|
|
end else begin
|
|
// keep old instance, just add a designer
|
|
DebugLn(['TMainIDE.DoLoadLFM Creating designer for hidden component of ',AnUnitInfo.Filename]);
|
|
end;
|
|
finally
|
|
MissingClasses.Free;
|
|
if ReferencesLocked then begin
|
|
if Project1<>nil then
|
|
Project1.UnlockUnitComponentDependencies;
|
|
end;
|
|
end;
|
|
|
|
NewComponent:=AnUnitInfo.Component;
|
|
// create the designer (if not already done)
|
|
if ([ofProjectLoading,ofLoadHiddenResource]*OpenFlags=[]) then
|
|
FormEditor1.ClearSelection;
|
|
{$IFDEF IDE_DEBUG}
|
|
DebugLn('SUCCESS: streaming lfm="',LFMBuf.Filename,'"');
|
|
{$ENDIF}
|
|
AnUnitInfo.ComponentName:=NewComponent.Name;
|
|
AnUnitInfo.ComponentResourceName:=AnUnitInfo.ComponentName;
|
|
DesignerForm := nil;
|
|
if not (ofLoadHiddenResource in OpenFlags) then
|
|
begin
|
|
DesignerForm := FormEditor1.GetDesignerForm(NewComponent);
|
|
if (DesignerForm=nil) or (DesignerForm.Designer=nil) then
|
|
DesignerForm := CreateDesignerForComponent(AnUnitInfo,NewComponent);
|
|
end;
|
|
|
|
// select the new form (object inspector, formeditor, control selection)
|
|
if (DesignerForm <> nil)
|
|
and ([ofProjectLoading,ofLoadHiddenResource] * OpenFlags=[]) then
|
|
begin
|
|
FDisplayState := dsForm;
|
|
GlobalDesignHook.LookupRoot := NewComponent;
|
|
TheControlSelection.AssignPersistent(NewComponent);
|
|
end;
|
|
|
|
// show new form
|
|
if DesignerForm <> nil then
|
|
begin
|
|
DesignerForm.ControlStyle := DesignerForm.ControlStyle - [csNoDesignVisible];
|
|
if NewComponent is TControl then
|
|
TControl(NewComponent).ControlStyle:= TControl(NewComponent).ControlStyle - [csNoDesignVisible];
|
|
LCLIntf.ShowWindow(DesignerForm.Handle, ShowCommands[AnUnitInfo.ComponentState]);
|
|
FLastFormActivated := DesignerForm;
|
|
end;
|
|
|
|
{$IFDEF IDE_DEBUG}
|
|
debugln('[TMainIDE.DoLoadLFM] LFM end');
|
|
{$ENDIF}
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.FindBaseComponentClass(const AComponentClassName,
|
|
DescendantClassName: string;
|
|
out AComponentClass: TComponentClass): boolean;
|
|
// returns false if an error occured
|
|
// Important: returns true even if AComponentClass=nil
|
|
begin
|
|
// find the ancestor class
|
|
if AComponentClassName<>'' then begin
|
|
if (DescendantClassName<>'')
|
|
and (SysUtils.CompareText(AComponentClassName,'TCustomForm')=0) then begin
|
|
// this is a common user mistake
|
|
MessageDlg(lisCodeTemplError, Format(
|
|
lisTheResourceClassDescendsFromProbablyThisIsATypoFor, ['"',
|
|
DescendantClassName, '"', '"', AComponentClassName, '"']),
|
|
mtError,[mbCancel],0);
|
|
Result:=false;
|
|
exit;
|
|
end else if (DescendantClassName<>'')
|
|
and (SysUtils.CompareText(AComponentClassName,'TComponent')=0) then begin
|
|
// this is not yet implemented
|
|
MessageDlg(lisCodeTemplError, Format(
|
|
lisUnableToOpenDesignerTheClassDoesNotDescendFromADes, [#13,
|
|
DescendantClassName]),
|
|
mtError,[mbCancel],0);
|
|
Result:=false;
|
|
exit;
|
|
end else begin
|
|
// search in the registered base classes
|
|
AComponentClass:=FormEditor1.FindDesignerBaseClassByName(AComponentClassName,true);
|
|
end;
|
|
end else begin
|
|
// default is TForm
|
|
AComponentClass:=TForm;
|
|
end;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TMainIDE.DoFixupComponentReferences(
|
|
RootComponent: TComponent; OpenFlags: TOpenFlags): TModalResult;
|
|
var
|
|
RootUnitInfo: TUnitInfo;
|
|
UnitFilenames: TStrings;
|
|
ComponentNameToUnitFilename: TStringToStringTree;
|
|
|
|
procedure AddFile(List: TStrings; aFilename: string);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i:=0 to List.Count-1 do
|
|
if CompareFilenames(List[i],aFilename)=0 then exit;
|
|
List.Add(aFilename);
|
|
end;
|
|
|
|
procedure FindUsedUnits;
|
|
var
|
|
CurUnitFilenames: TStrings;
|
|
i: Integer;
|
|
UnitFilename: string;
|
|
LFMFilename: String;
|
|
LFMCode: TCodeBuffer;
|
|
LFMType: String;
|
|
LFMComponentName: String;
|
|
LFMClassName: String;
|
|
ModalResult: TModalResult;
|
|
CTResult: Boolean;
|
|
begin
|
|
if UnitFilenames<>nil then exit;
|
|
UnitFilenames:=TStringList.Create;
|
|
ComponentNameToUnitFilename:=TStringToStringTree.Create(false);
|
|
|
|
// search in the used units of RootUnitInfo
|
|
CurUnitFilenames:=nil;
|
|
try
|
|
CTResult:=CodeToolBoss.FindUsedUnitFiles(RootUnitInfo.Source,
|
|
CurUnitFilenames);
|
|
if not CTResult then begin
|
|
DebugLn(['TMainIDE.DoFixupComponentReferences.FindUsedUnits failed parsing ',RootUnitInfo.Filename]);
|
|
// ignore the error. This was just a fallback search.
|
|
end;
|
|
if (CurUnitFilenames<>nil) then begin
|
|
for i:=0 to CurUnitFilenames.Count-1 do
|
|
AddFile(UnitFilenames,CurUnitFilenames[i]);
|
|
end;
|
|
finally
|
|
CurUnitFilenames.Free;
|
|
end;
|
|
|
|
// search in the used units of the .lpr file
|
|
if RootUnitInfo.IsPartOfProject
|
|
and (Project1.MainUnitInfo<>nil)
|
|
and (Project1.MainUnitInfo.Source<>nil)
|
|
and (pfMainUnitIsPascalSource in Project1.Flags) then begin
|
|
CurUnitFilenames:=nil;
|
|
try
|
|
CTResult:=CodeToolBoss.FindUsedUnitFiles(Project1.MainUnitInfo.Source,
|
|
CurUnitFilenames);
|
|
if not CTResult then begin
|
|
DebugLn(['TMainIDE.DoFixupComponentReferences.FindUsedUnits failed parsing ',Project1.MainUnitInfo.Filename]);
|
|
// ignore the error. This was just a fallback search.
|
|
end;
|
|
if (CurUnitFilenames<>nil) then begin
|
|
for i:=0 to CurUnitFilenames.Count-1 do
|
|
AddFile(UnitFilenames,CurUnitFilenames[i]);
|
|
end;
|
|
finally
|
|
CurUnitFilenames.Free;
|
|
end;
|
|
end;
|
|
|
|
// parse once all available component names in all .lfm files
|
|
for i:=0 to UnitFilenames.Count-1 do begin
|
|
UnitFilename:=UnitFilenames[i];
|
|
LFMFilename:=ChangeFileExt(UnitFilename,'.lfm');
|
|
if not FileExistsCached(LFMFilename) then
|
|
LFMFilename:=ChangeFileExt(UnitFilename,'.dfm');
|
|
if FileExistsCached(LFMFilename) then begin
|
|
// load the lfm file
|
|
ModalResult:=LoadCodeBuffer(LFMCode,LFMFilename,[lbfCheckIfText],true);
|
|
if ModalResult<>mrOk then begin
|
|
debugln('TMainIDE.DoFixupComponentReferences Failed loading ',LFMFilename);
|
|
if ModalResult=mrAbort then break;
|
|
end else begin
|
|
// read the LFM component name
|
|
ReadLFMHeader(LFMCode.Source,LFMType,LFMComponentName,LFMClassName);
|
|
if LFMComponentName<>'' then
|
|
ComponentNameToUnitFilename.Add(LFMComponentName,UnitFilename);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function FindUnitFilename(const aComponentName: string): string;
|
|
var
|
|
RefUnitInfo: TUnitInfo;
|
|
UnitFilename: string;
|
|
begin
|
|
if RootUnitInfo.IsPartOfProject then begin
|
|
// search in the project component names
|
|
RefUnitInfo:=Project1.UnitWithComponentName(aComponentName,true);
|
|
if RefUnitInfo<>nil then begin
|
|
Result:=RefUnitInfo.Filename;
|
|
exit;
|
|
end;
|
|
end;
|
|
// ToDo: search in owner+used packages
|
|
|
|
FindUsedUnits;
|
|
|
|
// search in the used units
|
|
if (ComponentNameToUnitFilename<>nil) then begin
|
|
UnitFilename:=ComponentNameToUnitFilename[aComponentName];
|
|
if UnitFilename<>'' then begin
|
|
Result:=UnitFilename;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
DebugLn(['FindUnitFilename missing: ',aComponentName]);
|
|
Result:='';
|
|
end;
|
|
|
|
function LoadDependencyHidden(const RefRootName: string): TModalResult;
|
|
var
|
|
LFMFilename: String;
|
|
UnitCode, LFMCode: TCodeBuffer;
|
|
ModalResult: TModalResult;
|
|
UnitFilename: String;
|
|
RefUnitInfo: TUnitInfo;
|
|
begin
|
|
Result:=mrCancel;
|
|
|
|
// load lfm
|
|
UnitFilename:=FindUnitFilename(RefRootName);
|
|
if UnitFilename='' then begin
|
|
DebugLn(['TMainIDE.DoFixupComponentReferences.LoadDependencyHidden failed to find lfm for "',RefRootName,'"']);
|
|
exit(mrCancel);
|
|
end;
|
|
LFMFilename:=ChangeFileExt(UnitFilename,'.lfm');
|
|
if not FileExistsUTF8(LFMFilename) then
|
|
LFMFilename:=ChangeFileExt(UnitFilename,'.dfm');
|
|
ModalResult:=LoadCodeBuffer(LFMCode,LFMFilename,[lbfCheckIfText],false);
|
|
if ModalResult<>mrOk then begin
|
|
debugln('TMainIDE.DoFixupComponentReferences Failed loading ',LFMFilename);
|
|
exit(mrCancel);
|
|
end;
|
|
|
|
RefUnitInfo:=Project1.UnitInfoWithFilename(UnitFilename);
|
|
// create unit info
|
|
if RefUnitInfo=nil then begin
|
|
RefUnitInfo:=TUnitInfo.Create(nil);
|
|
RefUnitInfo.Filename:=UnitFilename;
|
|
Project1.AddFile(RefUnitInfo,false);
|
|
end;
|
|
|
|
if RefUnitInfo.Source = nil then
|
|
begin
|
|
ModalResult := LoadCodeBuffer(UnitCode, UnitFileName, [lbfCheckIfText],false);
|
|
if ModalResult<>mrOk then begin
|
|
debugln('TMainIDE.DoFixupComponentReferences Failed loading ',UnitFilename);
|
|
exit(mrCancel);
|
|
end;
|
|
RefUnitInfo.Source := UnitCode;
|
|
end;
|
|
|
|
if RefUnitInfo.Component<>nil then begin
|
|
Result:=mrOk;
|
|
exit;
|
|
end;
|
|
|
|
if RefUnitInfo.LoadingComponent then begin
|
|
Result:=mrRetry;
|
|
exit;
|
|
end;
|
|
|
|
// load resource hidden
|
|
Result:=DoLoadLFM(RefUnitInfo,LFMCode,
|
|
OpenFlags+[ofLoadHiddenResource],[]);
|
|
//DebugLn(['LoadDependencyHidden ',dbgsname(RefUnitInfo.Component)]);
|
|
end;
|
|
|
|
procedure GatherRootComponents(AComponent: TComponent; List: TFPList);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
List.Add(AComponent);
|
|
for i:=0 to AComponent.ComponentCount-1 do
|
|
if csInline in AComponent.Components[i].ComponentState then
|
|
GatherRootComponents(AComponent.Components[i],List);
|
|
end;
|
|
|
|
var
|
|
CurRoot: TComponent;
|
|
i, j: Integer;
|
|
RefRootName: string;
|
|
RootComponents: TFPList;
|
|
ReferenceRootNames: TStringList;
|
|
ReferenceInstanceNames: TStringList;
|
|
LoadResult: TModalResult;
|
|
LoadingReferenceNames: TStringList;
|
|
begin
|
|
Result:=mrOk;
|
|
CurRoot:=RootComponent;
|
|
while CurRoot.Owner<>nil do
|
|
CurRoot:=CurRoot.Owner;
|
|
RootUnitInfo:=Project1.UnitWithComponent(CurRoot);
|
|
if RootUnitInfo=nil then exit;
|
|
|
|
UnitFilenames:=nil;
|
|
ComponentNameToUnitFilename:=nil;
|
|
RootComponents:=TFPList.Create;
|
|
ReferenceRootNames:=TStringList.Create;
|
|
ReferenceInstanceNames:=TStringList.Create;
|
|
LoadingReferenceNames:=TStringList.Create;
|
|
try
|
|
BeginFixupComponentReferences;
|
|
GatherRootComponents(RootComponent,RootComponents);
|
|
for i:=0 to RootComponents.Count-1 do begin
|
|
CurRoot:=TComponent(RootComponents[i]);
|
|
|
|
// load referenced components
|
|
ReferenceRootNames.Clear;
|
|
GetFixupReferenceNames(CurRoot,ReferenceRootNames);
|
|
for j:=0 to ReferenceRootNames.Count-1 do begin
|
|
RefRootName:=ReferenceRootNames[j];
|
|
ReferenceInstanceNames.Clear;
|
|
GetFixupInstanceNames(CurRoot,RefRootName,ReferenceInstanceNames);
|
|
|
|
DebugLn(['TMainIDE.DoFixupComponentReferences UNRESOLVED BEFORE loading ',j,' Root=',dbgsName(CurRoot),' RefRoot=',RefRootName,' Refs="',Trim(ReferenceInstanceNames.Text),'"']);
|
|
|
|
// load the referenced component
|
|
LoadResult:=LoadDependencyHidden(RefRootName);
|
|
|
|
if LoadResult=mrRetry then begin
|
|
// the other component is still loading
|
|
// this means both components reference each other
|
|
LoadingReferenceNames.Add(RefRootName);
|
|
end
|
|
else if LoadResult<>mrOk then begin
|
|
// ToDo: give a nice error message and give user the choice between
|
|
// a) ignore and loose the references
|
|
// b) undo the opening (close the designer forms)
|
|
DebugLn(['TMainIDE.DoFixupComponentReferences failed loading component ',RefRootName]);
|
|
Result:=mrCancel;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// fixup references
|
|
try
|
|
GlobalFixupReferences;
|
|
except
|
|
on E: Exception do begin
|
|
DebugLn(['TMainIDE.DoFixupComponentReferences GlobalFixupReferences ',E.Message]);
|
|
DumpExceptionBackTrace;
|
|
end;
|
|
end;
|
|
|
|
for i:=0 to RootComponents.Count-1 do begin
|
|
CurRoot:=TComponent(RootComponents[i]);
|
|
// clean up dangling references
|
|
ReferenceRootNames.Clear;
|
|
GetFixupReferenceNames(CurRoot,ReferenceRootNames);
|
|
for j:=0 to ReferenceRootNames.Count-1 do begin
|
|
RefRootName:=ReferenceRootNames[j];
|
|
if AnsiSearchInStringList(LoadingReferenceNames,RefRootName)>=0
|
|
then
|
|
continue;
|
|
ReferenceInstanceNames.Clear;
|
|
GetFixupInstanceNames(CurRoot,RefRootName,ReferenceInstanceNames);
|
|
DebugLn(['TMainIDE.DoFixupComponentReferences UNRESOLVED AFTER loading ',j,' ',dbgsName(CurRoot),' RefRoot=',RefRootName,' Refs="',Trim(ReferenceInstanceNames.Text),'"']);
|
|
|
|
// forget the rest of the dangling references
|
|
RemoveFixupReferences(CurRoot,RefRootName);
|
|
end;
|
|
end;
|
|
finally
|
|
EndFixupComponentReferences;
|
|
LoadingReferenceNames.Free;
|
|
RootComponents.Free;
|
|
UnitFilenames.Free;
|
|
ComponentNameToUnitFilename.Free;
|
|
ReferenceRootNames.Free;
|
|
ReferenceInstanceNames.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.BeginFixupComponentReferences;
|
|
begin
|
|
inc(FFixingGlobalComponentLock);
|
|
if FFixingGlobalComponentLock=1 then
|
|
RegisterFindGlobalComponentProc(@FindDesignComponent);
|
|
end;
|
|
|
|
procedure TMainIDE.EndFixupComponentReferences;
|
|
begin
|
|
dec(FFixingGlobalComponentLock);
|
|
if FFixingGlobalComponentLock=0 then
|
|
UnregisterFindGlobalComponentProc(@FindDesignComponent);
|
|
end;
|
|
|
|
function TMainIDE.DoLoadAncestorDependencyHidden(AnUnitInfo: TUnitInfo;
|
|
const DescendantClassName: string;
|
|
OpenFlags: TOpenFlags;
|
|
out AncestorClass: TComponentClass;
|
|
out AncestorUnitInfo: TUnitInfo): TModalResult;
|
|
var
|
|
AncestorClassName: String;
|
|
CodeBuf: TCodeBuffer;
|
|
begin
|
|
AncestorClassName:='';
|
|
AncestorClass:=nil;
|
|
AncestorUnitInfo:=nil;
|
|
|
|
// find the ancestor type in the source
|
|
if AnUnitInfo.Source=nil then begin
|
|
Result:=LoadCodeBuffer(CodeBuf,AnUnitInfo.Filename,
|
|
[lbfUpdateFromDisk,lbfCheckIfText],true);
|
|
if Result<>mrOk then exit;
|
|
AnUnitInfo.Source:=CodeBuf;
|
|
end;
|
|
if not CodeToolBoss.FindFormAncestor(AnUnitInfo.Source,DescendantClassName,
|
|
AncestorClassName,true)
|
|
then begin
|
|
DebugLn('TMainIDE.DoLoadAncestorDependencyHidden Filename="',AnUnitInfo.Filename,'" ClassName=',DescendantClassName,'. Unable to find ancestor class: ',CodeToolBoss.ErrorMessage);
|
|
end;
|
|
|
|
// try the base designer classes
|
|
if not FindBaseComponentClass(AncestorClassName,DescendantClassName,
|
|
AncestorClass) then
|
|
begin
|
|
DebugLn(['TMainIDE.DoLoadAncestorDependencyHidden FindUnitComponentClass failed for AncestorClassName=',AncestorClassName]);
|
|
exit(mrCancel);
|
|
end;
|
|
|
|
// try loading the ancestor first (unit, lfm and component instance)
|
|
if (AncestorClass=nil) then begin
|
|
Result:=DoLoadComponentDependencyHidden(AnUnitInfo,AncestorClassName,
|
|
OpenFlags,false,AncestorClass,AncestorUnitInfo);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TMainIDE.DoLoadAncestorDependencyHidden DoLoadComponentDependencyHidden failed AnUnitInfo=',AnUnitInfo.Filename]);
|
|
end;
|
|
case Result of
|
|
mrAbort: exit;
|
|
mrOk: ;
|
|
mrIgnore:
|
|
begin
|
|
// use TForm as default
|
|
AncestorClass:=TForm;
|
|
AncestorUnitInfo:=nil;
|
|
end;
|
|
else
|
|
// cancel
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
// use TForm as default ancestor
|
|
if AncestorClass=nil then
|
|
AncestorClass:=TForm;
|
|
//DebugLn('TMainIDE.DoLoadAncestorDependencyHidden Filename="',AnUnitInfo.Filename,'" AncestorClassName=',AncestorClassName,' AncestorClass=',dbgsName(AncestorClass));
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoLoadComponentDependencyHidden(AnUnitInfo: TUnitInfo;
|
|
const AComponentClassName: string; Flags: TOpenFlags;
|
|
MustHaveLFM: boolean;
|
|
var AComponentClass: TComponentClass; var ComponentUnitInfo: TUnitInfo
|
|
): TModalResult;
|
|
var
|
|
CTErrorMsg: string;
|
|
CTErrorCode: TCodeBuffer;
|
|
CTErrorLine: LongInt;
|
|
CTErrorCol: LongInt;
|
|
|
|
function FindClassInUnit(UnitCode: TCodeBuffer;
|
|
out TheModalResult: TModalResult;
|
|
var LFMCode: TCodeBuffer;
|
|
var ClassFound: boolean): boolean;
|
|
var
|
|
AncestorClassName: String;
|
|
UsedFilename: String;
|
|
UsingFilename: String;
|
|
LFMFilename: String;
|
|
AComponentName: String;
|
|
begin
|
|
Result:=false;
|
|
TheModalResult:=mrCancel;
|
|
LFMCode:=nil;
|
|
ClassFound:=false;
|
|
|
|
AncestorClassName:='';
|
|
if not CodeToolBoss.FindFormAncestor(UnitCode,AComponentClassName,
|
|
AncestorClassName,true) then
|
|
begin
|
|
if CodeToolBoss.ErrorMessage<>'' then begin
|
|
CTErrorMsg:=CodeToolBoss.ErrorMessage;
|
|
CTErrorCode:=CodeToolBoss.ErrorCode;
|
|
CTErrorLine:=CodeToolBoss.ErrorLine;
|
|
CTErrorCol:=CodeToolBoss.ErrorColumn;
|
|
end;
|
|
exit;
|
|
end;
|
|
|
|
// this unit contains the class
|
|
ClassFound:=true;
|
|
LFMFilename:=ChangeFileExt(UnitCode.Filename,'.lfm');
|
|
if FileExistsUTF8(LFMFilename) then begin
|
|
UsingFilename:=AnUnitInfo.Filename;
|
|
Project1.ConvertToLPIFilename(UsingFilename);
|
|
UsedFilename:=UnitCode.Filename;
|
|
Project1.ConvertToLPIFilename(UsedFilename);
|
|
TheModalResult:=QuestionDlg(lisCodeTemplError,
|
|
Format(lisClassConflictsWithLfmFileTheUnitUsesTheUnitWhic, [#13,
|
|
UsingFilename, #13, UsedFilename, #13, AComponentClassName, #13, #13,
|
|
#13, AComponentClassName]),
|
|
mtError,
|
|
[mrCancel, lisCancelLoadingThisComponent,
|
|
mrAbort, lisAbortWholeLoading,
|
|
mrIgnore, lisIgnoreUseTFormAsAncestor], 0);
|
|
exit;
|
|
end;
|
|
// there is no .lfm file
|
|
|
|
// create a dummy lfm file
|
|
LFMCode:=CodeToolBoss.CreateFile(LFMFilename);
|
|
if LFMCode=nil then begin
|
|
debugln('TMainIDE.DoLoadComponentDependencyHidden Failed creating dummy lfm ',LFMFilename);
|
|
exit;
|
|
end;
|
|
AComponentName:=AComponentClassName;
|
|
if AComponentName[1] in ['T','t'] then
|
|
AComponentName:=copy(AComponentName,2,length(AComponentName));
|
|
LFMCode.Source:=
|
|
'inherited '+AComponentName+': '+AComponentClassName+LineEnding
|
|
+'end';
|
|
|
|
Result:=true;
|
|
TheModalResult:=mrOk;
|
|
end;
|
|
|
|
function TryUnit(const UnitFilename: string; out TheModalResult: TModalResult;
|
|
TryWithoutLFM: boolean): boolean;
|
|
// returns true if the unit contains the component class and sets
|
|
// TheModalResult to the result of the loading
|
|
var
|
|
LFMFilename: String;
|
|
LFMCode: TCodeBuffer;
|
|
LFMClassName: string;
|
|
LFMType: string;
|
|
CurUnitInfo: TUnitInfo;
|
|
UnitCode: TCodeBuffer;
|
|
begin
|
|
Result:=false;
|
|
TheModalResult:=mrCancel;
|
|
if not FilenameIsPascalUnit(UnitFilename) then exit;
|
|
|
|
CurUnitInfo:=Project1.UnitInfoWithFilename(UnitFilename);
|
|
if (CurUnitInfo<>nil) and (CurUnitInfo.Component<>nil) then
|
|
begin
|
|
// unit with loaded component found -> check if it is the right one
|
|
//DebugLn(['TMainIDE.DoLoadComponentDependencyHidden unit with a component found CurUnitInfo=',CurUnitInfo.Filename,' ',dbgsName(CurUnitInfo.Component)]);
|
|
if SysUtils.CompareText(CurUnitInfo.Component.ClassName,AComponentClassName)=0
|
|
then begin
|
|
// component found (it was already loaded)
|
|
ComponentUnitInfo:=CurUnitInfo;
|
|
AComponentClass:=TComponentClass(ComponentUnitInfo.Component.ClassType);
|
|
Result:=true;
|
|
TheModalResult:=mrOk;
|
|
end else begin
|
|
// this unit does not have this component
|
|
end;
|
|
exit;
|
|
end;
|
|
|
|
if not TryWithoutLFM then begin
|
|
LFMFilename:=ChangeFileExt(UnitFilename,'.lfm');
|
|
if not FileExistsUTF8(LFMFilename) then
|
|
LFMFilename:=ChangeFileExt(UnitFilename,'.dfm');
|
|
if FileExistsUTF8(LFMFilename) then begin
|
|
// load the lfm file
|
|
TheModalResult:=LoadCodeBuffer(LFMCode,LFMFilename,[lbfCheckIfText],true);
|
|
if TheModalResult<>mrOk then begin
|
|
debugln('TMainIDE.DoLoadComponentDependencyHidden Failed loading ',LFMFilename);
|
|
exit;
|
|
end;
|
|
// read the LFM classname
|
|
ReadLFMHeader(LFMCode.Source,LFMClassName,LFMType);
|
|
if LFMType='' then ;
|
|
if SysUtils.CompareText(LFMClassName,AComponentClassName)<>0 then exit;
|
|
|
|
// .lfm found
|
|
Result:=true;
|
|
end else if not TryWithoutLFM then begin
|
|
// unit has no .lfm
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
{$ifdef VerboseFormEditor}
|
|
debugln('TMainIDE.DoLoadComponentDependencyHidden ',AnUnitInfo.Filename,' Loading referenced form ',UnitFilename);
|
|
{$endif}
|
|
// load unit source
|
|
TheModalResult:=LoadCodeBuffer(UnitCode,UnitFilename,[lbfCheckIfText],true);
|
|
if TheModalResult<>mrOk then begin
|
|
debugln('TMainIDE.DoLoadComponentDependencyHidden Failed loading ',UnitFilename);
|
|
exit;
|
|
end;
|
|
|
|
if TryWithoutLFM then begin
|
|
if not FindClassInUnit(UnitCode,TheModalResult,LFMCode,Result) then exit;
|
|
end;
|
|
|
|
// create unit info
|
|
if CurUnitInfo=nil then begin
|
|
CurUnitInfo:=TUnitInfo.Create(UnitCode);
|
|
CurUnitInfo.ReadUnitNameFromSource(true);
|
|
Project1.AddFile(CurUnitInfo,false);
|
|
end;
|
|
|
|
// load resource hidden
|
|
TheModalResult:=DoLoadLFM(CurUnitInfo,LFMCode,
|
|
Flags+[ofLoadHiddenResource],[]);
|
|
if (TheModalResult=mrOk) then begin
|
|
ComponentUnitInfo:=CurUnitInfo;
|
|
AComponentClass:=TComponentClass(ComponentUnitInfo.Component.ClassType);
|
|
{$ifdef VerboseFormEditor}
|
|
debugln('TMainIDE.DoLoadComponentDependencyHidden Wanted=',AComponentClassName,' Class=',AComponentClass.ClassName);
|
|
{$endif}
|
|
TheModalResult:=mrOk;
|
|
end else begin
|
|
debugln('TMainIDE.DoLoadComponentDependencyHidden Failed to load component ',AComponentClassName);
|
|
if TheModalResult<>mrAbort then
|
|
TheModalResult:=mrCancel;
|
|
end;
|
|
end;
|
|
|
|
function TryRegisteredClasses(out TheModalResult: TModalResult): boolean;
|
|
begin
|
|
Result:=false;
|
|
AComponentClass:=
|
|
FormEditor1.FindDesignerBaseClassByName(AComponentClassName,true);
|
|
if AComponentClass<>nil then begin
|
|
DebugLn(['TMainIDE.DoLoadComponentDependencyHidden.TryRegisteredClasses found: ',AComponentClass.ClassName]);
|
|
TheModalResult:=mrOk;
|
|
Result:=true;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
UsedUnitFilenames: TStrings;
|
|
i: Integer;
|
|
begin
|
|
Result:=mrCancel;
|
|
CTErrorMsg:='';
|
|
CTErrorCode:=nil;
|
|
CTErrorLine:=0;
|
|
CTErrorCol:=0;
|
|
|
|
if (AComponentClassName='') or (not IsValidIdent(AComponentClassName)) then
|
|
begin
|
|
DebugLn(['TMainIDE.DoLoadComponentDependencyHidden invalid component class name "',AComponentClassName,'"']);
|
|
exit(mrCancel);
|
|
end;
|
|
|
|
// check for circles
|
|
if AnUnitInfo.LoadingComponent then begin
|
|
Result:=QuestionDlg(lisCodeTemplError, Format(
|
|
lisUnableToLoadTheComponentClassBecauseItDependsOnIts, ['"',
|
|
AComponentClassName, '"']),
|
|
mtError, [mrCancel, lisCancelLoadingThisComponent,
|
|
mrAbort, lisAbortWholeLoading], 0);
|
|
exit;
|
|
end;
|
|
|
|
AnUnitInfo.LoadingComponent:=true;
|
|
try
|
|
// search component lfm
|
|
{$ifdef VerboseFormEditor}
|
|
debugln('TMainIDE.DoLoadComponentDependencyHidden ',AnUnitInfo.Filename,' AComponentClassName=',AComponentClassName,' AComponentClass=',dbgsName(AComponentClass));
|
|
{$endif}
|
|
// first search the resource of ComponentUnitInfo
|
|
if ComponentUnitInfo<>nil then begin
|
|
if TryUnit(ComponentUnitInfo.Filename,Result,false) then exit;
|
|
end;
|
|
|
|
// then try registered global classes
|
|
if TryRegisteredClasses(Result) then exit;
|
|
|
|
// finally search in used units
|
|
UsedUnitFilenames:=nil;
|
|
try
|
|
if not CodeToolBoss.FindUsedUnitFiles(AnUnitInfo.Source,UsedUnitFilenames)
|
|
then begin
|
|
DoJumpToCodeToolBossError;
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
|
|
if (UsedUnitFilenames<>nil) then begin
|
|
// search for every used unit the .lfm file
|
|
for i:=UsedUnitFilenames.Count-1 downto 0 do begin
|
|
if TryUnit(UsedUnitFilenames[i],Result,false) then exit;
|
|
end;
|
|
// search in every used unit the class
|
|
if not MustHaveLFM then
|
|
for i:=UsedUnitFilenames.Count-1 downto 0 do begin
|
|
if TryUnit(UsedUnitFilenames[i],Result,true) then exit;
|
|
end;
|
|
if CTErrorMsg<>'' then begin
|
|
// class not found and there was a parser error
|
|
// maybe that's the reason, why the class was not found
|
|
// show the user
|
|
if ([ofProjectLoading,ofQuiet]*Flags=[]) then begin
|
|
CodeToolBoss.SetError(CTErrorCode,CTErrorLine,CTErrorCol,CTErrorMsg);
|
|
DoJumpToCodeToolBossError;
|
|
Result:=mrAbort;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
UsedUnitFilenames.Free;
|
|
end;
|
|
|
|
// not found => tell the user
|
|
Result:=QuestionDlg(lisCodeTemplError, Format(
|
|
lisUnableToFindTheUnitOfComponentClass, ['"', AComponentClassName, '"']),
|
|
mtError, [mrCancel, lisCancelLoadingThisComponent,
|
|
mrAbort, lisAbortWholeLoading,
|
|
mrIgnore, lisIgnoreUseTFormAsAncestor], 0);
|
|
finally
|
|
AnUnitInfo.LoadingComponent:=false;
|
|
end;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
function TMainIDE.CloseUnitComponent
|
|
|
|
Params: AnUnitInfo: TUnitInfo
|
|
Result: TModalResult;
|
|
|
|
Free the designer form of a unit.
|
|
And free all unused components.
|
|
-------------------------------------------------------------------------------}
|
|
function TMainIDE.CloseUnitComponent(AnUnitInfo: TUnitInfo; Flags: TCloseFlags
|
|
): TModalResult;
|
|
|
|
procedure FreeUnusedComponents;
|
|
var
|
|
CompUnitInfo: TUnitInfo;
|
|
begin
|
|
CompUnitInfo:=Project1.FirstUnitWithComponent;
|
|
Project1.UpdateUnitComponentDependencies;
|
|
while CompUnitInfo<>nil do begin
|
|
//DebugLn(['FreeUnusedComponents ',CompUnitInfo.Filename,' ',dbgsName(CompUnitInfo.Component),' UnitComponentIsUsed=',UnitComponentIsUsed(CompUnitInfo,true)]);
|
|
if not UnitComponentIsUsed(CompUnitInfo,true) then begin
|
|
// close the unit component
|
|
CloseUnitComponent(CompUnitInfo,Flags);
|
|
// this has recursively freed all components, so exit here
|
|
exit;
|
|
end;
|
|
CompUnitInfo:=CompUnitInfo.NextUnitWithComponent;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
AForm: TCustomForm;
|
|
OldDesigner: TDesigner;
|
|
LookupRoot: TComponent;
|
|
ComponentStillUsed: Boolean;
|
|
begin
|
|
LookupRoot:=AnUnitInfo.Component;
|
|
if LookupRoot=nil then exit(mrOk);
|
|
{$IFDEF VerboseIDEMultiForm}
|
|
DebugLn(['TMainIDE.CloseUnitComponent ',AnUnitInfo.Filename,' ',dbgsName(LookupRoot)]);
|
|
{$ENDIF}
|
|
|
|
Project1.LockUnitComponentDependencies; // avoid circles
|
|
try
|
|
// save
|
|
if (cfSaveFirst in Flags) and (AnUnitInfo.OpenEditorInfoCount > 0)
|
|
and (not AnUnitInfo.IsReverting) then begin
|
|
Result:=DoSaveEditorFile(AnUnitInfo.OpenEditorInfo[0].EditorComponent,[sfCheckAmbiguousFiles]);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TMainIDE.CloseUnitComponent DoSaveEditorFile failed']);
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
// close dependencies
|
|
if cfCloseDependencies in Flags then begin
|
|
{$IFDEF VerboseIDEMultiForm}
|
|
DebugLn(['TMainIDE.CloseUnitComponent cfCloseDependencies ',AnUnitInfo.Filename,' ',dbgsName(LookupRoot)]);
|
|
{$ENDIF}
|
|
Result:=CloseDependingUnitComponents(AnUnitInfo,Flags);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TMainIDE.CloseUnitComponent CloseDependingUnitComponents failed']);
|
|
exit;
|
|
end;
|
|
// now only soft dependencies are left. The component can be freed.
|
|
end;
|
|
|
|
AForm:=FormEditor1.GetDesignerForm(LookupRoot);
|
|
OldDesigner:=nil;
|
|
if AForm<>nil then
|
|
OldDesigner:=TDesigner(AForm.Designer);
|
|
if FLastFormActivated=AForm then
|
|
FLastFormActivated:=nil;
|
|
ComponentStillUsed:=(not (cfCloseDependencies in Flags))
|
|
and UnitComponentIsUsed(AnUnitInfo,false);
|
|
{$IFDEF VerboseTFrame}
|
|
DebugLn(['TMainIDE.CloseUnitComponent ',AnUnitInfo.Filename,' ComponentStillUsed=',ComponentStillUsed,' UnitComponentIsUsed=',UnitComponentIsUsed(AnUnitInfo,false),' ',dbgs(AnUnitInfo.Flags),' DepAncestor=',AnUnitInfo.FindUsedByComponentDependency([ucdtAncestor])<>nil,' DepInline=',AnUnitInfo.FindUsedByComponentDependency([ucdtInlineClass])<>nil]);
|
|
{$ENDIF}
|
|
if (OldDesigner=nil) then begin
|
|
// hidden component
|
|
//DebugLn(['TMainIDE.CloseUnitComponent freeing hidden component without designer: ',AnUnitInfo.Filename,' ',DbgSName(AnUnitInfo.Component)]);
|
|
if ComponentStillUsed then begin
|
|
// hidden component is still used => keep it
|
|
{$IFDEF VerboseIDEMultiForm}
|
|
DebugLn(['TMainIDE.CloseUnitComponent hidden component is still used => keep it ',AnUnitInfo.Filename,' ',DbgSName(AnUnitInfo.Component)]);
|
|
{$ENDIF}
|
|
end else begin
|
|
// hidden component is not used => free it
|
|
{$IFDEF VerboseIDEMultiForm}
|
|
DebugLn(['TMainIDE.CloseUnitComponent hidden component is not used => free it ',AnUnitInfo.Filename,' ',DbgSName(AnUnitInfo.Component)]);
|
|
{$ENDIF}
|
|
try
|
|
FormEditor1.DeleteComponent(LookupRoot,true);
|
|
finally
|
|
AnUnitInfo.Component:=nil;
|
|
end;
|
|
FreeUnusedComponents;
|
|
end;
|
|
end else begin
|
|
// component with designer
|
|
if ComponentStillUsed then begin
|
|
// free designer, keep component hidden
|
|
{$IFDEF VerboseIDEMultiForm}
|
|
DebugLn(['TMainIDE.CloseUnitComponent hiding component and freeing designer: ',AnUnitInfo.Filename,' ',DbgSName(AnUnitInfo.Component)]);
|
|
{$ENDIF}
|
|
AnUnitInfo.LoadedDesigner:=false;
|
|
OldDesigner.FreeDesigner(false);
|
|
end else begin
|
|
// free designer and design form
|
|
{$IFDEF VerboseIDEMultiForm}
|
|
DebugLn(['TMainIDE.CloseUnitComponent freeing component and designer: ',AnUnitInfo.Filename,' ',DbgSName(AnUnitInfo.Component)]);
|
|
{$ENDIF}
|
|
try
|
|
AnUnitInfo.LoadedDesigner:=false;
|
|
OldDesigner.FreeDesigner(true);
|
|
finally
|
|
AnUnitInfo.Component:=nil;
|
|
end;
|
|
end;
|
|
Project1.InvalidateUnitComponentDesignerDependencies;
|
|
FreeUnusedComponents;
|
|
end;
|
|
finally
|
|
Project1.UnlockUnitComponentDependencies;
|
|
end;
|
|
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.CloseDependingUnitComponents(AnUnitInfo: TUnitInfo;
|
|
Flags: TCloseFlags): TModalResult;
|
|
var
|
|
UserAsked: Boolean;
|
|
|
|
function CloseNext(var ModResult: TModalresult;
|
|
Types: TUnitCompDependencyTypes): boolean;
|
|
var
|
|
DependingUnitInfo: TUnitInfo;
|
|
DependenciesFlags: TCloseFlags;
|
|
begin
|
|
repeat
|
|
DependingUnitInfo:=Project1.UnitUsingComponentUnit(AnUnitInfo,Types);
|
|
if DependingUnitInfo=nil then break;
|
|
if (not UserAsked) and (not (cfQuiet in Flags))
|
|
and (not DependingUnitInfo.IsReverting) then begin
|
|
// ToDo: collect in advance all components to close and show user the list
|
|
ModResult:=IDEQuestionDialog('Close component?',
|
|
'Close component '+dbgsName(DependingUnitInfo.Component)+'?',
|
|
mtConfirmation,[mrYes,mrAbort]);
|
|
if ModResult<>mrYes then exit(false);
|
|
UserAsked:=true;
|
|
end;
|
|
// close recursively
|
|
DependenciesFlags:=Flags+[cfCloseDependencies];
|
|
if cfSaveDependencies in Flags then
|
|
Include(DependenciesFlags,cfSaveFirst);
|
|
ModResult:=CloseUnitComponent(DependingUnitInfo,DependenciesFlags);
|
|
if ModResult<>mrOk then exit(false);
|
|
until false;
|
|
Result:=true;
|
|
end;
|
|
|
|
begin
|
|
UserAsked:=false;
|
|
Project1.LockUnitComponentDependencies;
|
|
try
|
|
// Important:
|
|
// This function is called recursively.
|
|
// It is important that first the hard, non cyclic dependencies
|
|
// are freed in the correct order.
|
|
// After that the soft, cyclic dependencies can be freed in any order.
|
|
|
|
// first close all descendants recursively
|
|
// This must happen in the right order (descendants before ancestor)
|
|
if not CloseNext(Result,[ucdtAncestor]) then exit;
|
|
|
|
// then close all nested descendants recursively
|
|
// This must happen in the right order (nested descendants before ancestor)
|
|
if not CloseNext(Result,[ucdtInlineClass]) then exit;
|
|
|
|
// then close all referring components
|
|
// These can build circles and can be freed in any order.
|
|
if not CloseNext(Result,[ucdtProperty]) then exit;
|
|
finally
|
|
Project1.UnlockUnitComponentDependencies;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.UnitComponentIsUsed(AnUnitInfo: TUnitInfo;
|
|
CheckHasDesigner: boolean): boolean;
|
|
// if CheckHasDesigner=true and AnUnitInfo has a designer (visible) return true
|
|
// otherwise check if another unit needs AnUnitInfo
|
|
var
|
|
LookupRoot: TComponent;
|
|
begin
|
|
Result:=false;
|
|
LookupRoot:=AnUnitInfo.Component;
|
|
if LookupRoot=nil then exit;
|
|
// check if a designer or another component uses this component
|
|
Project1.UpdateUnitComponentDependencies;
|
|
if Project1.UnitComponentIsUsed(AnUnitInfo,CheckHasDesigner) then
|
|
exit(true);
|
|
//DebugLn(['TMainIDE.UnitComponentIsUsed ',AnUnitInfo.Filename,' ',dbgs(AnUnitInfo.Flags)]);
|
|
end;
|
|
|
|
function TMainIDE.RemoveFilesFromProject(AProject: TProject; UnitInfos: TFPList
|
|
): TModalResult;
|
|
var
|
|
i: Integer;
|
|
AnUnitInfo: TUnitInfo;
|
|
ShortUnitName: String;
|
|
Dummy: Boolean;
|
|
ObsoleteUnitPaths: String;
|
|
ObsoleteIncPaths: String;
|
|
p: Integer;
|
|
ProjUnitPaths: String;
|
|
CurDir: String;
|
|
ResolvedDir: String;
|
|
OldP: LongInt;
|
|
ProjIncPaths: String;
|
|
begin
|
|
Result:=mrOk;
|
|
if UnitInfos=nil then exit;
|
|
// check if something will change
|
|
i:=UnitInfos.Count-1;
|
|
while (i>=0) and (not TUnitInfo(UnitInfos[i]).IsPartOfProject) do dec(i);
|
|
if i<0 then exit(mrOk);
|
|
// check ToolStatus
|
|
if (ToolStatus in [itCodeTools,itCodeToolAborting]) then begin
|
|
debugln('TMainIDE.RemoveUnitsFromProject wrong ToolStatus ',dbgs(ord(ToolStatus)));
|
|
exit;
|
|
end;
|
|
// commit changes from source editor to codetools
|
|
SaveSourceEditorChangesToCodeCache(nil);
|
|
|
|
ObsoleteUnitPaths:='';
|
|
ObsoleteIncPaths:='';
|
|
AProject.BeginUpdate(true);
|
|
try
|
|
for i:=0 to UnitInfos.Count-1 do begin
|
|
AnUnitInfo:=TUnitInfo(UnitInfos[i]);
|
|
//debugln(['TMainIDE.RemoveUnitsFromProject Unit ',AnUnitInfo.Filename]);
|
|
if not AnUnitInfo.IsPartOfProject then continue;
|
|
AnUnitInfo.IsPartOfProject:=false;
|
|
AProject.Modified:=true;
|
|
if FilenameIsPascalUnit(AnUnitInfo.Filename) then begin
|
|
if FilenameIsAbsolute(AnUnitInfo.Filename) then
|
|
ObsoleteUnitPaths:=MergeSearchPaths(ObsoleteUnitPaths,
|
|
ChompPathDelim(ExtractFilePath(AnUnitInfo.Filename)));
|
|
// remove from project's unit section
|
|
if (AProject.MainUnitID>=0)
|
|
and (pfMainUnitHasUsesSectionForAllUnits in AProject.Flags)
|
|
then begin
|
|
ShortUnitName:=ExtractFileNameOnly(AnUnitInfo.Filename);
|
|
//debugln(['TMainIDE.RemoveUnitsFromProject UnitName=',ShortUnitName]);
|
|
if (ShortUnitName<>'') then begin
|
|
Dummy:=CodeToolBoss.RemoveUnitFromAllUsesSections(
|
|
AProject.MainUnitInfo.Source,ShortUnitName);
|
|
if not Dummy then begin
|
|
DoJumpToCodeToolBossError;
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
// remove CreateForm statement from project
|
|
if (AProject.MainUnitID>=0)
|
|
and (pfMainUnitHasCreateFormStatements in AProject.Flags)
|
|
and (AnUnitInfo.ComponentName<>'') then begin
|
|
Dummy:=AProject.RemoveCreateFormFromProjectFile(
|
|
'T'+AnUnitInfo.ComponentName,AnUnitInfo.ComponentName);
|
|
if not Dummy then begin
|
|
DoJumpToCodeToolBossError;
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
if CompareFileExt(AnUnitInfo.Filename,'.inc',false)=0 then begin
|
|
// include file
|
|
if FilenameIsAbsolute(AnUnitInfo.Filename) then
|
|
ObsoleteIncPaths:=MergeSearchPaths(ObsoleteIncPaths,
|
|
ChompPathDelim(ExtractFilePath(AnUnitInfo.Filename)));
|
|
end;
|
|
end;
|
|
|
|
// removed directories still used fomr ObsoleteUnitPaths, ObsoleteIncPaths
|
|
AnUnitInfo:=AProject.FirstPartOfProject;
|
|
while AnUnitInfo<>nil do begin
|
|
if FilenameIsAbsolute(AnUnitInfo.Filename) then begin
|
|
if FilenameIsPascalUnit(AnUnitInfo.Filename) then
|
|
ObsoleteUnitPaths:=RemoveSearchPaths(ObsoleteUnitPaths,
|
|
ChompPathDelim(ExtractFilePath(AnUnitInfo.Filename)));
|
|
if CompareFileExt(AnUnitInfo.Filename,'.inc',false)=0 then
|
|
ObsoleteIncPaths:=RemoveSearchPaths(ObsoleteIncPaths,
|
|
ChompPathDelim(ExtractFilePath(AnUnitInfo.Filename)));
|
|
end;
|
|
AnUnitInfo:=AnUnitInfo.NextPartOfProject;
|
|
end;
|
|
|
|
// check if compiler options contain paths of ObsoleteUnitPaths
|
|
if ObsoleteUnitPaths<>'' then begin
|
|
ProjUnitPaths:=AProject.CompilerOptions.OtherUnitFiles;
|
|
p:=1;
|
|
repeat
|
|
OldP:=p;
|
|
CurDir:=GetNextDirectoryInSearchPath(ProjUnitPaths,p);
|
|
if CurDir='' then break;
|
|
ResolvedDir:=AProject.CompilerOptions.ParsedOpts.DoParseOption(CurDir,
|
|
pcosUnitPath,false);
|
|
if (ResolvedDir<>'')
|
|
and (SearchDirectoryInSearchPath(ObsoleteUnitPaths,ResolvedDir)>0) then begin
|
|
if IDEQuestionDialog(lisRemoveUnitPath,
|
|
Format(lisTheDirectoryContainsNoProjectUnitsAnyMoreRemoveThi, [
|
|
CurDir]),
|
|
mtConfirmation, [mrYes, lisLazBuildRemove, mrNo, lisKeep2], '')=
|
|
mrYes
|
|
then begin
|
|
// remove
|
|
ProjUnitPaths:=RemoveSearchPaths(ProjUnitPaths,CurDir);
|
|
p:=OldP;
|
|
end;
|
|
end;
|
|
until false;
|
|
AProject.CompilerOptions.OtherUnitFiles:=ProjUnitPaths;
|
|
end;
|
|
|
|
// check if compiler options contain paths of ObsoleteIncPaths
|
|
if ObsoleteIncPaths<>'' then begin
|
|
ProjIncPaths:=AProject.CompilerOptions.IncludePath;
|
|
p:=1;
|
|
repeat
|
|
OldP:=p;
|
|
CurDir:=GetNextDirectoryInSearchPath(ProjIncPaths,p);
|
|
if CurDir='' then break;
|
|
ResolvedDir:=AProject.CompilerOptions.ParsedOpts.DoParseOption(CurDir,
|
|
pcosIncludePath,false);
|
|
if (ResolvedDir<>'')
|
|
and (SearchDirectoryInSearchPath(ObsoleteIncPaths,ResolvedDir)>0) then begin
|
|
if IDEQuestionDialog(lisRemoveIncludePath,
|
|
Format(lisTheDirectoryContainsNoProjectIncludeFilesAnyMoreRe, [
|
|
CurDir]),
|
|
mtConfirmation, [mrYes, lisLazBuildRemove, mrNo, lisKeep2], '')=
|
|
mrYes
|
|
then begin
|
|
// remove
|
|
ProjIncPaths:=RemoveSearchPaths(ProjIncPaths,CurDir);
|
|
p:=OldP;
|
|
end;
|
|
end;
|
|
until false;
|
|
AProject.CompilerOptions.IncludePath:=ProjIncPaths;
|
|
end;
|
|
|
|
finally
|
|
ApplyCodeToolChanges;
|
|
AProject.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.GetAncestorUnit(AnUnitInfo: TUnitInfo): TUnitInfo;
|
|
begin
|
|
if (AnUnitInfo=nil) or (AnUnitInfo.Component=nil) then
|
|
Result:=nil
|
|
else
|
|
Result:=AnUnitInfo.FindAncestorUnit;
|
|
end;
|
|
|
|
function TMainIDE.GetAncestorLookupRoot(AnUnitInfo: TUnitInfo): TComponent;
|
|
var
|
|
AncestorUnit: TUnitInfo;
|
|
begin
|
|
AncestorUnit:=GetAncestorUnit(AnUnitInfo);
|
|
if AncestorUnit<>nil then
|
|
Result:=AncestorUnit.Component
|
|
else
|
|
Result:=nil;
|
|
end;
|
|
|
|
procedure TMainIDE.UpdateSaveMenuItemsAndButtons(UpdateSaveAll: boolean);
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
GetCurrentUnit(SrcEdit,AnUnitInfo);
|
|
// menu items
|
|
if UpdateSaveAll then
|
|
MainIDEBar.itmProjectSave.Enabled :=
|
|
SomethingOfProjectIsModified
|
|
or ((Project1<>nil) and Project1.IsVirtual);
|
|
MainIDEBar.itmFileSave.Enabled :=
|
|
((SrcEdit<>nil) and SrcEdit.Modified)
|
|
or ((AnUnitInfo<>nil) and (AnUnitInfo.IsVirtual));
|
|
if UpdateSaveAll then
|
|
MainIDEBar.itmFileSaveAll.Enabled := MainIDEBar.itmProjectSave.Enabled;
|
|
// toolbar buttons
|
|
MainIDEBar.BuildModeSpeedButton.Visible:=(Project1<>nil)
|
|
and (Project1.BuildModes.Count>1);
|
|
MainIDEBar.SaveSpeedBtn.Enabled := MainIDEBar.itmFileSave.Enabled;
|
|
if UpdateSaveAll then
|
|
MainIDEBar.SaveAllSpeedBtn.Enabled := MainIDEBar.itmFileSaveAll.Enabled;
|
|
end;
|
|
|
|
function TMainIDE.CreateProjectObject(ProjectDesc,
|
|
FallbackProjectDesc: TProjectDescriptor): TProject;
|
|
begin
|
|
Result:=TProject.Create(ProjectDesc);
|
|
// custom initialization
|
|
Result.BeginUpdate(true);
|
|
if ProjectDesc.InitProject(Result)<>mrOk then begin
|
|
Result.EndUpdate;
|
|
Result.Free;
|
|
Result:=nil;
|
|
if FallbackProjectDesc=nil then exit;
|
|
Result:=TProject.Create(FallbackProjectDesc);
|
|
FallbackProjectDesc.InitProject(Result);
|
|
end
|
|
else
|
|
Result.EndUpdate;
|
|
|
|
Result.MainProject:=true;
|
|
Result.OnFileBackup:=@MainBuildBoss.BackupFile;
|
|
Result.OnLoadProjectInfo:=@OnLoadProjectInfoFromXMLConfig;
|
|
Result.OnSaveProjectInfo:=@OnSaveProjectInfoToXMLConfig;
|
|
Result.OnSaveUnitSessionInfo:=@OnSaveProjectUnitSessionInfo;
|
|
Result.OnGetTestDirectory:=@OnProjectGetTestDirectory;
|
|
Result.OnChangeProjectInfoFile:=@OnProjectChangeInfoFile;
|
|
Result.OnBeforeRead:=@DoProjectOptionsBeforeRead;
|
|
Result.OnAfterWrite:=@DoProjectOptionsAfterWrite;
|
|
end;
|
|
|
|
procedure TMainIDE.OnSaveProjectUnitSessionInfo(AUnitInfo: TUnitInfo);
|
|
|
|
function GetWindowState(ACustomForm: TCustomForm): TWindowState;
|
|
begin
|
|
Result := wsNormal;
|
|
if ACustomForm.HandleAllocated then
|
|
if IsIconic(ACustomForm.Handle) then
|
|
Result := wsMinimized
|
|
else
|
|
if IsZoomed(ACustomForm.Handle) then
|
|
Result := wsMaximized;
|
|
end;
|
|
var
|
|
DesignerForm: TCustomForm;
|
|
begin
|
|
if (AUnitInfo.Component <> nil) then
|
|
begin
|
|
DesignerForm := FormEditor1.GetDesignerForm(AUnitInfo.Component);
|
|
if DesignerForm <> nil then
|
|
AUnitInfo.ComponentState := GetWindowState(DesignerForm);
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.SaveProjectInfo(var Flags: TSaveFlags): TModalResult;
|
|
var
|
|
MainUnitInfo: TUnitInfo;
|
|
MainUnitSrcEdit: TSourceEditor;
|
|
DestFilename: String;
|
|
SkipSavingMainSource: Boolean;
|
|
begin
|
|
Project1.ActiveWindowIndexAtStart := SourceEditorManager.ActiveSourceWindowIndex;
|
|
|
|
// update source notebook page names
|
|
UpdateSourceNames;
|
|
|
|
// find mainunit
|
|
GetMainUnit(MainUnitInfo,MainUnitSrcEdit,true);
|
|
|
|
// save project specific settings of the source editor
|
|
SaveSourceEditorProjectSpecificSettings;
|
|
|
|
if Project1.IsVirtual
|
|
and (not (sfDoNotSaveVirtualFiles in Flags)) then
|
|
Include(Flags,sfSaveAs);
|
|
if ([sfSaveAs,sfSaveToTestDir]*Flags=[sfSaveAs]) then begin
|
|
// let user choose a filename
|
|
Result:=DoShowSaveProjectAsDialog(sfSaveMainSourceAs in Flags);
|
|
if Result<>mrOk then exit;
|
|
Flags:=Flags-[sfSaveAs,sfSaveMainSourceAs];
|
|
end;
|
|
|
|
// update HasResources information
|
|
DoUpdateProjectResourceInfo;
|
|
|
|
// save project info file
|
|
if (not (sfSaveToTestDir in Flags))
|
|
and (not Project1.IsVirtual) then begin
|
|
Result:=Project1.WriteProject([],'');
|
|
if Result=mrAbort then exit;
|
|
EnvironmentOptions.LastSavedProjectFile:=Project1.ProjectInfoFile;
|
|
IDEProtocolOpts.LastProjectLoadingCrashed := False;
|
|
AddRecentProjectFileToEnvironment(Project1.ProjectInfoFile);
|
|
SaveIncludeLinks;
|
|
UpdateCaption;
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
|
|
// save main source
|
|
if (MainUnitInfo<>nil) and (not (sfDoNotSaveVirtualFiles in flags)) then
|
|
begin
|
|
if not (sfSaveToTestDir in Flags) then
|
|
DestFilename := MainUnitInfo.Filename
|
|
else
|
|
DestFilename := MainBuildBoss.GetTestUnitFilename(MainUnitInfo);
|
|
|
|
if MainUnitInfo.OpenEditorInfoCount > 0 then
|
|
begin
|
|
// loaded in source editor
|
|
Result:=DoSaveEditorFile(MainUnitInfo.OpenEditorInfo[0].EditorComponent,
|
|
[sfProjectSaving]+[sfSaveToTestDir,sfCheckAmbiguousFiles]*Flags);
|
|
if Result=mrAbort then exit;
|
|
end else
|
|
begin
|
|
// not loaded in source editor (hidden)
|
|
SkipSavingMainSource := false;
|
|
if not (sfSaveToTestDir in Flags) and not MainUnitInfo.NeedsSaveToDisk then
|
|
SkipSavingMainSource := true;
|
|
if (not SkipSavingMainSource) and (MainUnitInfo.Source<>nil) then
|
|
begin
|
|
Result:=SaveCodeBufferToFile(MainUnitInfo.Source, DestFilename);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
end;
|
|
|
|
// clear modified flags
|
|
if not (sfSaveToTestDir in Flags) then
|
|
begin
|
|
if (Result=mrOk) then begin
|
|
if MainUnitInfo<>nil then MainUnitInfo.ClearModifieds;
|
|
if MainUnitSrcEdit<>nil then MainUnitSrcEdit.Modified:=false;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
procedure TMainIDE.OnLoadProjectInfoFromXMLConfig(TheProject: TProject;
|
|
XMLConfig: TXMLConfig; Merge: boolean);
|
|
begin
|
|
if TheProject=Project1 then
|
|
DebugBoss.LoadProjectSpecificInfo(XMLConfig,Merge);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSaveProjectInfoToXMLConfig(TheProject: TProject;
|
|
XMLConfig: TXMLConfig; WriteFlags: TProjectWriteFlags);
|
|
begin
|
|
if (TheProject=Project1) and (not (pwfSkipDebuggerSettings in WriteFlags))
|
|
then
|
|
DebugBoss.SaveProjectSpecificInfo(XMLConfig,WriteFlags);
|
|
end;
|
|
|
|
procedure TMainIDE.OnProjectGetTestDirectory(TheProject: TProject;
|
|
out TestDir: string);
|
|
begin
|
|
TestDir:=GetTestBuildDirectory;
|
|
end;
|
|
|
|
procedure TMainIDE.OnProjectChangeInfoFile(TheProject: TProject);
|
|
begin
|
|
if TheProject<>Project1 then exit;
|
|
if TheProject.IsVirtual then
|
|
CodeToolBoss.SetGlobalValue(ExternalMacroStart+'ProjPath',VirtualDirectory)
|
|
else
|
|
CodeToolBoss.SetGlobalValue(ExternalMacroStart+'ProjPath',
|
|
Project1.ProjectDirectory)
|
|
end;
|
|
|
|
procedure TMainIDE.GetMainUnit(var MainUnitInfo: TUnitInfo;
|
|
var MainUnitSrcEdit: TSourceEditor; UpdateModified: boolean);
|
|
begin
|
|
MainUnitSrcEdit:=nil;
|
|
if Project1.MainUnitID>=0 then begin
|
|
MainUnitInfo:=Project1.MainUnitInfo;
|
|
if MainUnitInfo.OpenEditorInfoCount > 0 then begin
|
|
MainUnitSrcEdit := TSourceEditor(MainUnitInfo.OpenEditorInfo[0].EditorComponent);
|
|
if UpdateModified and MainUnitSrcEdit.Modified
|
|
then begin
|
|
MainUnitSrcEdit.UpdateCodeBuffer;
|
|
MainUnitInfo.Modified:=true;
|
|
end;
|
|
end;
|
|
end else
|
|
MainUnitInfo:=nil;
|
|
end;
|
|
|
|
procedure TMainIDE.SaveSrcEditorProjectSpecificSettings(AnEditorInfo: TUnitEditorInfo);
|
|
var
|
|
ASrcEdit: TSourceEditor;
|
|
begin
|
|
ASrcEdit := TSourceEditor(AnEditorInfo.EditorComponent);
|
|
if ASrcEdit=nil then exit;
|
|
AnEditorInfo.TopLine:=ASrcEdit.EditorComponent.TopLine;
|
|
AnEditorInfo.CursorPos:=ASrcEdit.EditorComponent.CaretXY;
|
|
AnEditorInfo.FoldState := ASrcEdit.EditorComponent.FoldState;
|
|
end;
|
|
|
|
procedure TMainIDE.SaveSourceEditorProjectSpecificSettings;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to Project1.AllEditorsInfoCount - 1 do
|
|
SaveSrcEditorProjectSpecificSettings(Project1.AllEditorsInfo[i]);
|
|
end;
|
|
|
|
function TMainIDE.DoShowSaveProjectAsDialog(UseMainSourceFile: boolean): TModalResult;
|
|
var
|
|
MainUnitSrcEdit: TSourceEditor;
|
|
MainUnitInfo: TUnitInfo;
|
|
SaveDialog: TSaveDialog;
|
|
NewLPIFilename, NewProgramFilename, NewProgramName, AText, ACaption,
|
|
Ext: string;
|
|
NewBuf: TCodeBuffer;
|
|
OldProjectDir: string;
|
|
TitleWasDefault: Boolean;
|
|
OldSource: String;
|
|
AFilename: String;
|
|
NewTargetFilename: String;
|
|
begin
|
|
Project1.BeginUpdate(false);
|
|
try
|
|
OldProjectDir:=Project1.ProjectDirectory;
|
|
|
|
if Project1.MainUnitInfo = nil then
|
|
UseMainSourceFile := False;
|
|
|
|
SaveDialog:=TSaveDialog.Create(nil);
|
|
try
|
|
InputHistories.ApplyFileDialogSettings(SaveDialog);
|
|
AFilename:='';
|
|
// build a nice project info filename suggestion
|
|
if UseMainSourceFile and (Project1.MainUnitID>=0) then
|
|
AFilename:=Project1.MainUnitInfo.Unit_Name;
|
|
if AFilename='' then
|
|
AFilename:=ExtractFileName(Project1.ProjectInfoFile);
|
|
if AFilename='' then
|
|
AFilename:=ExtractFileName(Project1.MainFilename);
|
|
if AFilename='' then
|
|
AFilename:=Trim(Project1.Title);
|
|
if AFilename='' then
|
|
AFilename:='project1';
|
|
Ext := LowerCase(ExtractFileExt(AFilename));
|
|
if UseMainSourceFile then
|
|
begin
|
|
if (Ext = '') or (not FilenameIsPascalSource(AFilename)) then
|
|
AFilename := ChangeFileExt(AFilename, '.pas');
|
|
end else
|
|
begin
|
|
if (Ext = '') or FilenameIsPascalSource(AFilename) then
|
|
AFilename := ChangeFileExt(AFilename, '.lpi');
|
|
end;
|
|
Ext := ExtractFileExt(AFilename);
|
|
SaveDialog.Title := Format(lisSaveProject, [Project1.GetTitleOrName, Ext]);
|
|
SaveDialog.FileName := AFilename;
|
|
SaveDialog.Filter := '*' + Ext + '|' + '*' + Ext;
|
|
SaveDialog.DefaultExt := ExtractFileExt(AFilename);
|
|
if not Project1.IsVirtual then
|
|
SaveDialog.InitialDir := Project1.ProjectDirectory;
|
|
|
|
repeat
|
|
Result:=mrCancel;
|
|
NewLPIFilename:=''; // the project info file name
|
|
NewProgramName:=''; // the pascal program identifier
|
|
NewProgramFilename:=''; // the program source filename
|
|
|
|
if not SaveDialog.Execute then begin
|
|
// user cancels
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
AFilename:=ExpandFileNameUTF8(SaveDialog.FileName);
|
|
if not FilenameIsAbsolute(AFilename) then
|
|
RaiseException('TMainIDE.DoShowSaveProjectAsDialog: buggy ExpandFileNameUTF8');
|
|
|
|
// check program name
|
|
NewProgramName:=ExtractFileNameOnly(AFilename);
|
|
if (NewProgramName='') or (not IsValidIdent(NewProgramName)) then begin
|
|
Result:=MessageDlg(lisInvalidProjectFilename,
|
|
Format(lisisAnInvalidProjectNamePleaseChooseAnotherEGProject, ['"',
|
|
SaveDialog.Filename, '"', #13]),
|
|
mtInformation,[mbRetry,mbAbort],0);
|
|
if Result=mrAbort then exit;
|
|
continue; // try again
|
|
end;
|
|
|
|
// append default extension
|
|
if UseMainSourceFile then
|
|
begin
|
|
NewLPIFilename:=ChangeFileExt(AFilename,'.lpi');
|
|
end else
|
|
begin
|
|
NewLPIFilename:=AFilename;
|
|
if ExtractFileExt(NewLPIFilename)='' then
|
|
NewLPIFilename:=NewLPIFilename+'.lpi';
|
|
end;
|
|
|
|
// apply naming conventions
|
|
// rename to lowercase is not needed for main source
|
|
|
|
if Project1.MainUnitID >= 0 then
|
|
begin
|
|
// check mainunit filename
|
|
Ext := ExtractFileExt(Project1.MainUnitInfo.Filename);
|
|
if Ext = '' then Ext := '.pas';
|
|
if UseMainSourceFile then
|
|
NewProgramFilename := ExtractFileName(AFilename)
|
|
else
|
|
NewProgramFilename := ExtractFileNameWithoutExt(NewProgramName) + Ext;
|
|
NewProgramFilename := ExtractFilePath(NewLPIFilename) + NewProgramFilename;
|
|
if (CompareFilenames(NewLPIFilename, NewProgramFilename) = 0) then
|
|
begin
|
|
ACaption:=lisChooseADifferentName;
|
|
AText:=Format(lisTheProjectInfoFileIsEqualToTheProjectMainSource, [
|
|
'"', NewLPIFilename, '"', #13]);
|
|
Result:=MessageDlg(ACaption, AText, mtError, [mbAbort,mbRetry],0);
|
|
if Result=mrAbort then exit;
|
|
continue; // try again
|
|
end;
|
|
// check programname
|
|
if FilenameIsPascalUnit(NewProgramFilename)
|
|
and (Project1.IndexOfUnitWithName(NewProgramName,true,
|
|
Project1.MainUnitInfo)>=0) then
|
|
begin
|
|
ACaption:=lisUnitIdentifierExists;
|
|
AText:=Format(lisThereIsAUnitWithTheNameInTheProjectPleaseChoose, ['"',
|
|
NewProgramName, '"', #13]);
|
|
Result:=MessageDlg(ACaption,AText,mtError,[mbRetry,mbAbort],0);
|
|
if Result=mrAbort then exit;
|
|
continue; // try again
|
|
end;
|
|
Result:=mrOk;
|
|
end else begin
|
|
NewProgramFilename:='';
|
|
Result:=mrOk;
|
|
end;
|
|
until Result<>mrRetry;
|
|
finally
|
|
InputHistories.StoreFileDialogSettings(SaveDialog);
|
|
SaveDialog.Free;
|
|
end;
|
|
|
|
//DebugLn(['TMainIDE.DoShowSaveProjectAsDialog NewLPI=',NewLPIFilename,' NewProgramName=',NewProgramName,' NewMainSource=',NewProgramFilename]);
|
|
|
|
// check if info file or source file already exists
|
|
if FileExistsUTF8(NewLPIFilename) then
|
|
begin
|
|
ACaption:=lisOverwriteFile;
|
|
AText:=Format(lisAFileAlreadyExistsReplaceIt, ['"', NewLPIFilename, '"', #13]);
|
|
Result:=MessageDlg(ACaption, AText, mtConfirmation, [mbOk, mbCancel], 0);
|
|
if Result=mrCancel then exit;
|
|
end
|
|
else
|
|
begin
|
|
if FileExistsUTF8(NewProgramFilename) then
|
|
begin
|
|
ACaption:=lisOverwriteFile;
|
|
AText:=Format(lisAFileAlreadyExistsReplaceIt, ['"', NewProgramFilename,
|
|
'"', #13]);
|
|
Result:=MessageDlg(ACaption, AText, mtConfirmation,[mbOk,mbCancel],0);
|
|
if Result=mrCancel then exit;
|
|
end;
|
|
end;
|
|
|
|
TitleWasDefault := Project1.TitleIsDefault(true);
|
|
|
|
// set new project target filename
|
|
if (Project1.TargetFilename<>'')
|
|
and ((SysUtils.CompareText(ExtractFileNameOnly(Project1.TargetFilename),
|
|
ExtractFileNameOnly(Project1.ProjectInfoFile))=0)
|
|
or (Project1.ProjectInfoFile='')) then
|
|
begin
|
|
// target file is default => change, but keep sub directories
|
|
// Note: Extension is appended automatically => do not add it
|
|
NewTargetFilename:=ExtractFilePath(Project1.TargetFilename)
|
|
+ExtractFileNameOnly(NewProgramFilename);
|
|
Project1.TargetFilename:=NewTargetFilename;
|
|
//DebugLn(['TMainIDE.DoShowSaveProjectAsDialog changed targetfilename to ',Project1.TargetFilename]);
|
|
end;
|
|
|
|
// set new project filename
|
|
Project1.ProjectInfoFile:=NewLPIFilename;
|
|
EnvironmentOptions.AddToRecentProjectFiles(NewLPIFilename);
|
|
SetRecentProjectFilesMenu;
|
|
|
|
// change main source
|
|
if (Project1.MainUnitID >= 0) then
|
|
begin
|
|
GetMainUnit(MainUnitInfo, MainUnitSrcEdit, true);
|
|
|
|
if not Project1.ProjResources.RenameDirectives(MainUnitInfo.Filename,NewProgramFilename)
|
|
then begin
|
|
DebugLn(['TMainIDE.DoShowSaveProjectAsDialog failed renaming directives Old="',MainUnitInfo.Filename,'" New="',NewProgramFilename,'"']);
|
|
// silently ignore
|
|
end;
|
|
|
|
// Save old source code, to prevent overwriting it,
|
|
// if the file name didn't actually change.
|
|
OldSource := MainUnitInfo.Source.Source;
|
|
|
|
// switch MainUnitInfo.Source to new code
|
|
NewBuf := CodeToolBoss.CreateFile(NewProgramFilename);
|
|
if NewBuf=nil then begin
|
|
Result:=MessageDlg(lisErrorCreatingFile, Format(lisUnableToCreateFile3, [
|
|
#13, '"', NewProgramFilename, '"']), mtError, [mbCancel], 0);
|
|
exit;
|
|
end;
|
|
|
|
// copy the source to the new buffer
|
|
NewBuf.Source:=OldSource;
|
|
|
|
// assign the new buffer to the MainUnit
|
|
MainUnitInfo.Source:=NewBuf;
|
|
if MainUnitSrcEdit<>nil then
|
|
MainUnitSrcEdit.CodeBuffer:=NewBuf;
|
|
|
|
// change program name
|
|
MainUnitInfo.Unit_Name:=NewProgramName;
|
|
MainUnitInfo.Modified:=true;
|
|
|
|
// update source notebook page names
|
|
UpdateSourceNames;
|
|
end;
|
|
|
|
// update paths
|
|
Project1.CompilerOptions.OtherUnitFiles:=
|
|
RebaseSearchPath(Project1.CompilerOptions.OtherUnitFiles,OldProjectDir,
|
|
Project1.ProjectDirectory,true);
|
|
Project1.CompilerOptions.IncludePath:=
|
|
RebaseSearchPath(Project1.CompilerOptions.IncludePath,OldProjectDir,
|
|
Project1.ProjectDirectory,true);
|
|
Project1.CompilerOptions.Libraries:=
|
|
RebaseSearchPath(Project1.CompilerOptions.Libraries,OldProjectDir,
|
|
Project1.ProjectDirectory,true);
|
|
Project1.CompilerOptions.ObjectPath:=
|
|
RebaseSearchPath(Project1.CompilerOptions.ObjectPath,OldProjectDir,
|
|
Project1.ProjectDirectory,true);
|
|
Project1.CompilerOptions.SrcPath:=
|
|
RebaseSearchPath(Project1.CompilerOptions.SrcPath,OldProjectDir,
|
|
Project1.ProjectDirectory,true);
|
|
Project1.CompilerOptions.DebugPath:=
|
|
RebaseSearchPath(Project1.CompilerOptions.DebugPath,OldProjectDir,
|
|
Project1.ProjectDirectory,true);
|
|
|
|
// change title
|
|
if TitleWasDefault then begin
|
|
Project1.Title:=Project1.GetDefaultTitle;
|
|
// title does not need to be removed from source, because it was default
|
|
end;
|
|
|
|
// invalidate cached substituted macros
|
|
IncreaseCompilerParseStamp;
|
|
finally
|
|
Project1.EndUpdate;
|
|
end;
|
|
Result:=mrOk;
|
|
//DebugLn(['TMainIDE.DoShowSaveProjectAsDialog END OK']);
|
|
end;
|
|
|
|
function TMainIDE.DoCompleteLoadingProjectInfo: TModalResult;
|
|
begin
|
|
UpdateCaption;
|
|
EnvironmentOptions.LastSavedProjectFile:=Project1.ProjectInfoFile;
|
|
EnvironmentOptions.Save(false);
|
|
|
|
MainBuildBoss.SetBuildTargetProject1(false);
|
|
|
|
// load required packages
|
|
PkgBoss.OpenProjectDependencies(Project1,true);
|
|
|
|
Project1.DefineTemplates.AllChanged;
|
|
//DebugLn('TMainIDE.DoCompleteLoadingProjectInfo ',Project1.IDAsString);
|
|
Project1.DefineTemplates.Active:=true;
|
|
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
procedure TMainIDE.OnCopyFile(const Filename: string; var Copy: boolean; Data: TObject);
|
|
begin
|
|
if Data=nil then exit;
|
|
if Data is TPublishModuleOptions then begin
|
|
Copy:=TPublishModuleOptions(Data).FileCanBePublished(Filename);
|
|
//writeln('TMainIDE.OnCopyFile "',Filename,'" ',Copy);
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnCopyError(const ErrorData: TCopyErrorData;
|
|
var Handled: boolean; Data: TObject);
|
|
begin
|
|
case ErrorData.Error of
|
|
ceSrcDirDoesNotExists:
|
|
MessageDlg(lisCopyError2,
|
|
Format(lisSourceDirectoryDoesNotExist, ['"', ErrorData.Param1, '"']),
|
|
mtError,[mbCancel],0);
|
|
ceCreatingDirectory:
|
|
MessageDlg(lisCopyError2,
|
|
Format(lisUnableToCreateDirectory, ['"', ErrorData.Param1, '"']),
|
|
mtError,[mbCancel],0);
|
|
ceCopyFileError:
|
|
MessageDlg(lisCopyError2,
|
|
Format(lisUnableToCopyFileTo, ['"', ErrorData.Param1, '"', #13, '"',
|
|
ErrorData.Param1, '"']),
|
|
mtError,[mbCancel],0);
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoOpenFileInSourceEditor(AnEditorInfo: TUnitEditorInfo;
|
|
PageIndex, WindowIndex: integer; Flags: TOpenFlags): TModalResult;
|
|
var
|
|
NewSrcEdit: TSourceEditor;
|
|
AFilename: string;
|
|
NewCaretXY: TPoint;
|
|
NewTopLine: LongInt;
|
|
NewLeftChar: LongInt;
|
|
NewErrorLine: LongInt;
|
|
NewExecutionLine: LongInt;
|
|
FoldState: String;
|
|
SrcNotebook: TSourceNotebook;
|
|
AnUnitInfo: TUnitInfo;
|
|
AShareEditor: TSourceEditor;
|
|
begin
|
|
//debugln(['TMainIDE.DoOpenFileInSourceEditor ',AnEditorInfo.UnitInfo.Filename,' Window=',WindowIndex,'/',SourceEditorManager.SourceWindowCount,' Page=',PageIndex]);
|
|
AnUnitInfo := AnEditorInfo.UnitInfo;
|
|
AFilename:=AnUnitInfo.Filename;
|
|
if (WindowIndex < 0) then
|
|
SrcNotebook := SourceEditorManager.ActiveOrNewSourceWindow
|
|
else
|
|
if (WindowIndex >= SourceEditorManager.SourceWindowCount) then begin
|
|
SrcNotebook := SourceEditorManager.NewSourceWindow;
|
|
Project1.MoveUnitWindowIndex(WindowIndex, SourceEditorManager.ActiveSourceWindowIndex);
|
|
end
|
|
else
|
|
SrcNotebook := SourceEditorManager.SourceWindows[WindowIndex];
|
|
|
|
// get syntax highlighter type
|
|
AnUnitInfo.UpdateDefaultHighlighter(FilenameToLazSyntaxHighlighter(AFilename));
|
|
|
|
SrcNotebook.IncUpdateLock;
|
|
try
|
|
//DebugLn(['TMainIDE.DoOpenFileInSourceEditor Revert=',ofRevert in Flags,' ',AnUnitInfo.Filename,' PageIndex=',PageIndex]);
|
|
if (not (ofRevert in Flags)) or (PageIndex<0) then begin
|
|
// create a new source editor
|
|
|
|
// update marks and cursor positions in Project1, so that merging the old
|
|
// settings during restoration will work
|
|
SaveSourceEditorProjectSpecificSettings;
|
|
AShareEditor := nil;
|
|
if AnUnitInfo.OpenEditorInfoCount > 0 then
|
|
AShareEditor := TSourceEditor(AnUnitInfo.OpenEditorInfo[0].EditorComponent);
|
|
NewSrcEdit:=SrcNotebook.NewFile(CreateSrcEditPageName(AnUnitInfo.Unit_Name,
|
|
AFilename, AShareEditor),AnUnitInfo.Source, False, AShareEditor);
|
|
NewSrcEdit.EditorComponent.BeginUpdate;
|
|
MainIDEBar.itmFileClose.Enabled:=True;
|
|
MainIDEBar.itmFileCloseAll.Enabled:=True;
|
|
NewCaretXY := AnEditorInfo.CursorPos;
|
|
NewTopLine := AnEditorInfo.TopLine;
|
|
FoldState := AnEditorInfo.FoldState;
|
|
NewLeftChar:=1;
|
|
NewErrorLine:=-1;
|
|
NewExecutionLine:=-1;
|
|
end else begin
|
|
// revert code in existing source editor
|
|
NewSrcEdit:=SourceEditorManager.SourceEditorsByPage[WindowIndex, PageIndex];
|
|
NewCaretXY:=NewSrcEdit.EditorComponent.CaretXY;
|
|
NewTopLine:=NewSrcEdit.EditorComponent.TopLine;
|
|
FoldState := NewSrcEdit.EditorComponent.FoldState;
|
|
NewLeftChar:=NewSrcEdit.EditorComponent.LeftChar;
|
|
NewErrorLine:=NewSrcEdit.ErrorLine;
|
|
NewExecutionLine:=NewSrcEdit.ExecutionLine;
|
|
NewSrcEdit.EditorComponent.BeginUpdate;
|
|
if NewSrcEdit.CodeBuffer=AnUnitInfo.Source then begin
|
|
AnUnitInfo.Source.AssignTo(NewSrcEdit.EditorComponent.Lines,true);
|
|
end else
|
|
NewSrcEdit.CodeBuffer:=AnUnitInfo.Source;
|
|
AnUnitInfo.ClearModifieds;
|
|
//DebugLn(['TMainIDE.DoOpenFileInSourceEditor NewCaretXY=',dbgs(NewCaretXY),' NewTopLine=',NewTopLine]);
|
|
end;
|
|
|
|
NewSrcEdit.IsLocked := AnEditorInfo.IsLocked;
|
|
AnEditorInfo.EditorComponent := NewSrcEdit;
|
|
//debugln(['TMainIDE.DoOpenFileInSourceEditor ',AnUnitInfo.Filename,' ',AnUnitInfo.EditorIndex]);
|
|
|
|
// restore source editor settings
|
|
DebugBoss.DoRestoreDebuggerMarks(AnUnitInfo);
|
|
NewSrcEdit.SyntaxHighlighterType := AnEditorInfo.SyntaxHighlighter;
|
|
NewSrcEdit.EditorComponent.AfterLoadFromFile;
|
|
try
|
|
NewSrcEdit.EditorComponent.FoldState := FoldState;
|
|
except
|
|
MessageDlg(lisError, lisFailedToLoadFoldStat, mtError, [mbOK], 0);
|
|
end;
|
|
|
|
NewSrcEdit.EditorComponent.CaretXY:=NewCaretXY;
|
|
NewSrcEdit.EditorComponent.TopLine:=NewTopLine;
|
|
NewSrcEdit.EditorComponent.LeftChar:=NewLeftChar;
|
|
NewSrcEdit.ErrorLine:=NewErrorLine;
|
|
NewSrcEdit.ExecutionLine:=NewExecutionLine;
|
|
NewSrcEdit.ReadOnly:=AnUnitInfo.ReadOnly;
|
|
NewSrcEdit.Modified:=false;
|
|
|
|
// mark unit as loaded
|
|
NewSrcEdit.EditorComponent.EndUpdate;
|
|
AnUnitInfo.Loaded:=true;
|
|
finally
|
|
SrcNotebook.DecUpdateLock;
|
|
end;
|
|
|
|
// update statusbar and focus editor
|
|
if (not (ofProjectLoading in Flags)) then begin
|
|
SourceEditorManager.ActiveEditor := NewSrcEdit;
|
|
SourceEditorManager.ShowActiveWindowOnTop(True);
|
|
end;
|
|
SrcNoteBook.UpdateStatusBar;
|
|
SrcNotebook.BringToFront;
|
|
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoNewFile(NewFileDescriptor: TProjectFileDescriptor;
|
|
var NewFilename: string; const NewSource: string;
|
|
NewFlags: TNewFlags; NewOwner: TObject): TModalResult;
|
|
|
|
function BeautifySrc(const s: string): string;
|
|
begin
|
|
Result:=CodeToolBoss.SourceChangeCache.BeautifyCodeOptions.
|
|
BeautifyStatement(s,0);
|
|
end;
|
|
|
|
var
|
|
NewUnitInfo:TUnitInfo;
|
|
NewSrcEdit: TSourceEditor;
|
|
NewUnitName: string;
|
|
NewBuffer: TCodeBuffer;
|
|
OldUnitIndex: Integer;
|
|
AncestorType: TPersistentClass;
|
|
LFMFilename: String;
|
|
SearchFlags: TProjectFileSearchFlags;
|
|
LFMSourceText: String;
|
|
LFMCode: TCodeBuffer;
|
|
AProject: TProject;
|
|
LRSFilename: String;
|
|
ResType: TResourceType;
|
|
SrcNoteBook: TSourceNotebook;
|
|
AShareEditor: TSourceEditor;
|
|
DisableAutoSize: Boolean;
|
|
begin
|
|
//debugln('TMainIDE.DoNewEditorFile A NewFilename=',NewFilename);
|
|
// empty NewFilename is ok, it will be auto generated
|
|
SaveSourceEditorChangesToCodeCache(nil);
|
|
|
|
// convert macros in filename
|
|
if nfConvertMacros in NewFlags then begin
|
|
if not GlobalMacroList.SubstituteStr(NewFilename) then begin
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
if NewOwner is TProject then
|
|
AProject:=TProject(NewOwner)
|
|
else
|
|
AProject:=Project1;
|
|
|
|
// check if the new file fits into the project
|
|
Result:=NewFileDescriptor.CheckOwner(nfQuiet in NewFlags);
|
|
if Result<>mrOk then exit;
|
|
|
|
// create new codebuffer and apply naming conventions
|
|
Result:=CreateNewCodeBuffer(NewFileDescriptor,NewOwner,NewFilename,NewBuffer,
|
|
NewUnitName);
|
|
if Result<>mrOk then exit;
|
|
|
|
NewFilename:=NewBuffer.Filename;
|
|
OldUnitIndex:=AProject.IndexOfFilename(NewFilename);
|
|
if OldUnitIndex>=0 then begin
|
|
// the file is not really new
|
|
NewUnitInfo:=AProject.Units[OldUnitIndex];
|
|
// close form
|
|
Result:=CloseUnitComponent(NewUnitInfo,
|
|
[cfCloseDependencies,cfSaveDependencies]);
|
|
if Result<>mrOk then exit;
|
|
// assign source
|
|
NewUnitInfo.Source:=NewBuffer;
|
|
end else
|
|
NewUnitInfo:=TUnitInfo.Create(NewBuffer);
|
|
//debugln(['TMainIDE.DoNewFile ',NewUnitInfo.Filename,' ',NewFilename]);
|
|
NewUnitInfo.ImproveUnitNameCache(NewUnitName);
|
|
NewUnitInfo.BuildFileIfActive:=NewFileDescriptor.BuildFileIfActive;
|
|
NewUnitInfo.RunFileIfActive:=NewFileDescriptor.RunFileIfActive;
|
|
|
|
// create source code
|
|
//debugln('TMainIDE.DoNewEditorFile A nfCreateDefaultSrc=',nfCreateDefaultSrc in NewFlags,' ResourceClass=',dbgs(NewFileDescriptor.ResourceClass));
|
|
if nfCreateDefaultSrc in NewFlags then begin
|
|
if (NewFileDescriptor.ResourceClass<>nil) then begin
|
|
NewUnitInfo.ComponentName:=
|
|
AProject.NewUniqueComponentName(NewFileDescriptor.DefaultResourceName);
|
|
NewUnitInfo.ComponentResourceName:='';
|
|
end;
|
|
NewUnitInfo.CreateStartCode(NewFileDescriptor,NewUnitName);
|
|
end else begin
|
|
if nfBeautifySrc in NewFlags then
|
|
NewBuffer.Source:=BeautifySrc(NewSource)
|
|
else
|
|
NewBuffer.Source:=NewSource;
|
|
NewUnitInfo.Modified:=true;
|
|
end;
|
|
|
|
// add to project
|
|
with NewUnitInfo do begin
|
|
Loaded:=true;
|
|
IsPartOfProject:=(nfIsPartOfProject in NewFlags)
|
|
or (NewOwner is TProject)
|
|
or (AProject.FileIsInProjectDir(NewFilename)
|
|
and (not (nfIsNotPartOfProject in NewFlags)));
|
|
end;
|
|
if OldUnitIndex<0 then begin
|
|
Project1.AddFile(NewUnitInfo,
|
|
NewFileDescriptor.AddToProject
|
|
and NewFileDescriptor.IsPascalUnit
|
|
and NewUnitInfo.IsPartOfProject
|
|
and (pfMainUnitHasUsesSectionForAllUnits in Project1.Flags));
|
|
end;
|
|
|
|
// syntax highlighter type
|
|
NewUnitInfo.DefaultSyntaxHighlighter := FilenameToLazSyntaxHighlighter(NewFilename);
|
|
|
|
// required packages
|
|
if NewUnitInfo.IsPartOfProject and (NewFileDescriptor.RequiredPackages<>'')
|
|
then begin
|
|
if PkgBoss.AddProjectDependencies(Project1,NewFileDescriptor.RequiredPackages
|
|
)<>mrOk then exit;
|
|
end;
|
|
|
|
if nfOpenInEditor in NewFlags then begin
|
|
// open a new sourceeditor
|
|
SrcNoteBook := SourceEditorManager.ActiveOrNewSourceWindow;
|
|
AShareEditor := nil;
|
|
if NewUnitInfo.OpenEditorInfoCount > 0 then
|
|
AShareEditor := TSourceEditor(NewUnitInfo.OpenEditorInfo[0].EditorComponent);
|
|
NewSrcEdit := SrcNoteBook.NewFile(CreateSrcEditPageName(NewUnitInfo.Unit_Name,
|
|
NewUnitInfo.Filename, AShareEditor),
|
|
NewUnitInfo.Source, True, AShareEditor);
|
|
MainIDEBar.itmFileClose.Enabled:=True;
|
|
MainIDEBar.itmFileCloseAll.Enabled:=True;
|
|
NewSrcEdit.SyntaxHighlighterType:=NewUnitInfo.EditorInfo[0].SyntaxHighlighter;
|
|
NewUnitInfo.GetClosedOrNewEditorInfo.EditorComponent := NewSrcEdit;
|
|
NewSrcEdit.EditorComponent.CaretXY := Point(1,1);
|
|
|
|
// create component
|
|
AncestorType:=NewFileDescriptor.ResourceClass;
|
|
//DebugLn(['TMainIDE.DoNewFile AncestorType=',dbgsName(AncestorType),' ComponentName',NewUnitInfo.ComponentName]);
|
|
if AncestorType<>nil then begin
|
|
ResType:=MainBuildBoss.GetResourceType(NewUnitInfo);
|
|
LFMSourceText:=NewFileDescriptor.GetResourceSource(NewUnitInfo.ComponentName);
|
|
//DebugLn(['TMainIDE.DoNewFile LFMSourceText=',LFMSourceText]);
|
|
if LFMSourceText<>'' then begin
|
|
// the NewFileDescriptor provides a custom .lfm source
|
|
// -> put it into a new .lfm buffer and load it
|
|
LFMFilename:=ChangeFileExt(NewUnitInfo.Filename,'.lfm');
|
|
LFMCode:=CodeToolBoss.CreateFile(LFMFilename);
|
|
LFMCode.Source:=LFMSourceText;
|
|
//debugln('TMainIDE.DoNewEditorFile A ',LFMFilename);
|
|
Result:=DoLoadLFM(NewUnitInfo,LFMCode,[],[]);
|
|
//DebugLn(['TMainIDE.DoNewFile ',dbgsName(NewUnitInfo.Component),' ',dbgsName(NewUnitInfo.Component.ClassParent)]);
|
|
// make sure the .lrs file exists
|
|
if (ResType=rtLRS) and NewUnitInfo.IsVirtual then begin
|
|
LRSFilename:=ChangeFileExt(NewUnitInfo.Filename,'.lrs');
|
|
CodeToolBoss.CreateFile(LRSFilename);
|
|
end;
|
|
if (NewUnitInfo.Component<>nil)
|
|
and NewFileDescriptor.UseCreateFormStatements
|
|
and NewUnitInfo.IsPartOfProject
|
|
and Project1.AutoCreateForms
|
|
and (pfMainUnitHasCreateFormStatements in Project1.Flags) then
|
|
begin
|
|
Project1.AddCreateFormToProjectFile(NewUnitInfo.Component.ClassName,
|
|
NewUnitInfo.Component.Name);
|
|
end;
|
|
end else begin
|
|
// create a designer form for a form/datamodule/frame
|
|
//DebugLn(['TMainIDE.DoNewFile Name=',NewFileDescriptor.Name,' Class=',NewFileDescriptor.ClassName]);
|
|
DisableAutoSize:=true;
|
|
Result := CreateNewForm(NewUnitInfo, AncestorType, nil,
|
|
NewFileDescriptor.UseCreateFormStatements,
|
|
DisableAutoSize);
|
|
if DisableAutoSize and (NewUnitInfo.Component<>nil)
|
|
and (NewUnitInfo.Component is TControl) then
|
|
TControl(NewUnitInfo.Component).EnableAutoSizing;
|
|
end;
|
|
if Result<>mrOk then exit;
|
|
end;
|
|
|
|
// show form and select form
|
|
if NewUnitInfo.Component<>nil then begin
|
|
// show form
|
|
DoShowDesignerFormOfCurrentSrc;
|
|
end else begin
|
|
FDisplayState:= dsSource;
|
|
end;
|
|
end else begin
|
|
// do not open in editor
|
|
end;
|
|
|
|
// Update HasResources property (if the .lfm file was created separately)
|
|
if (not NewUnitInfo.HasResources)
|
|
and FilenameIsPascalUnit(NewUnitInfo.Filename) then begin
|
|
//debugln('TMainIDE.DoNewEditorFile no HasResources ',NewUnitInfo.Filename);
|
|
LFMFilename:=ChangeFileExt(NewUnitInfo.Filename,'.lfm');
|
|
SearchFlags:=[];
|
|
if NewUnitInfo.IsPartOfProject then
|
|
Include(SearchFlags,pfsfOnlyProjectFiles);
|
|
if NewUnitInfo.IsVirtual then
|
|
Include(SearchFlags,pfsfOnlyVirtualFiles);
|
|
if (AProject.UnitInfoWithFilename(LFMFilename,SearchFlags)<>nil) then begin
|
|
//debugln('TMainIDE.DoNewEditorFile no HasResources ',NewUnitInfo.Filename,' ResourceFile exists');
|
|
NewUnitInfo.HasResources:=true;
|
|
end;
|
|
end;
|
|
|
|
if (nfAskForFilename in NewFlags) then begin
|
|
// save and ask for filename
|
|
NewUnitInfo.Modified:=true;
|
|
Result:=DoSaveEditorFile(NewSrcEdit,[sfCheckAmbiguousFiles,sfSaveAs]);
|
|
if Result<>mrOk then exit;
|
|
end else if nfSave in NewFlags then begin
|
|
if (nfOpenInEditor in NewFlags) or NewBuffer.IsVirtual then begin
|
|
// save and ask for filename if needed
|
|
NewUnitInfo.Modified:=true;
|
|
Result:=DoSaveEditorFile(NewSrcEdit,[sfCheckAmbiguousFiles]);
|
|
if Result<>mrOk then exit;
|
|
end else begin
|
|
// save quiet
|
|
NewBuffer.Save;
|
|
end;
|
|
end;
|
|
|
|
Result:=mrOk;
|
|
//DebugLn('TMainIDE.DoNewEditorFile END ',NewUnitInfo.Filename);
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoNewUnit end');{$ENDIF}
|
|
end;
|
|
|
|
function TMainIDE.DoNewOther: TModalResult;
|
|
var
|
|
NewIDEItem: TNewIDEItemTemplate;
|
|
begin
|
|
Result:=ShowNewIDEItemDialog(NewIDEItem);
|
|
if Result<>mrOk then exit;
|
|
if NewIDEItem is TNewItemProjectFile then begin
|
|
// file
|
|
if TNewItemProjectFile(NewIDEItem).Descriptor<>nil then
|
|
TNewItemProjectFile(NewIDEItem).Descriptor.Owner:=Project1;
|
|
try
|
|
Result:=DoNewEditorFile(TNewItemProjectFile(NewIDEItem).Descriptor,
|
|
'','',[nfOpenInEditor,nfCreateDefaultSrc]);
|
|
finally
|
|
if TNewItemProjectFile(NewIDEItem).Descriptor<>nil then
|
|
TNewItemProjectFile(NewIDEItem).Descriptor.Owner:=nil;
|
|
end;
|
|
end else if NewIDEItem is TNewItemProject then begin
|
|
// project
|
|
//debugln('TMainIDE.DoNewOther ',dbgsName(TNewItemProject(NewIDEItem).Descriptor));
|
|
Result:=DoNewProject(TNewItemProject(NewIDEItem).Descriptor);
|
|
end else if NewIDEItem is TNewItemPackage then begin
|
|
// packages
|
|
PkgBoss.DoNewPackage;
|
|
end else begin
|
|
MessageDlg(ueNotImplCap,
|
|
lisSorryThisTypeIsNotYetImplemented,
|
|
mtInformation,[mbOk],0);
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.CreateFileDialogFilterForSourceEditorFiles(Filter: string;
|
|
out AllEditorExt, AllFilter: string);
|
|
var
|
|
i: Integer;
|
|
SrcEdit: TSourceEditor;
|
|
Ext: String;
|
|
begin
|
|
AllFilter:='|'+TFileDialog.ExtractAllFilterMasks(Filter)+';*.inc';
|
|
AllEditorExt:='|';
|
|
for i:=0 to SourceEditorManager.SourceEditorCount-1 do begin
|
|
SrcEdit:=SourceEditorManager.SourceEditors[i];
|
|
Ext:=ExtractFileExt(SrcEdit.FileName);
|
|
if Ext<>'' then begin
|
|
Ext:='*'+Ext;
|
|
if (TFileDialog.FindMaskInFilter(AllFilter,Ext)>0)
|
|
or (TFileDialog.FindMaskInFilter(AllEditorExt,Ext)>0) then continue;
|
|
if AllEditorExt<>'|' then
|
|
AllEditorExt:=AllEditorExt+';';
|
|
AllEditorExt:=AllEditorExt+Ext;
|
|
end;
|
|
end;
|
|
if AllEditorExt<>'|' then begin
|
|
System.Delete(AllEditorExt,1,1);
|
|
AllFilter:=AllFilter+';'+AllEditorExt;
|
|
end;
|
|
System.Delete(AllFilter,1,1);
|
|
end;
|
|
|
|
function TMainIDE.DoSaveEditorFile(PageIndex:integer;
|
|
Flags: TSaveFlags):TModalResult;
|
|
begin
|
|
Result := DoSaveEditorFile(
|
|
SourceEditorManager.ActiveSourceWindow.FindSourceEditorWithPageIndex(PageIndex),
|
|
Flags);
|
|
end;
|
|
|
|
function TMainIDE.DoSaveEditorFile(AEditor: TSourceEditorInterface;
|
|
Flags: TSaveFlags): TModalResult;
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
TestFilename, DestFilename: string;
|
|
ResourceCode, LFMCode: TCodeBuffer;
|
|
MainUnitInfo: TUnitInfo;
|
|
OldUnitName: String;
|
|
OldFilename: String;
|
|
NewUnitName: String;
|
|
NewFilename: String;
|
|
CanAbort: boolean;
|
|
WasVirtual: Boolean;
|
|
Confirm: Boolean;
|
|
SaveProjectFlags: TSaveFlags;
|
|
WasPascalSource: Boolean;
|
|
begin
|
|
{$IFDEF IDE_VERBOSE}
|
|
writeln('TMainIDE.DoSaveEditorFile A PageIndex=',PageIndex,' Flags=',SaveFlagsToString(Flags));
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoSaveEditorFile A');{$ENDIF}
|
|
Result:=mrCancel;
|
|
if not (ToolStatus in [itNone,itDebugger]) then begin
|
|
Result:=mrAbort;
|
|
exit;
|
|
end;
|
|
CanAbort:=[sfCanAbort,sfProjectSaving]*Flags<>[];
|
|
|
|
if AEditor=nil then exit;
|
|
AnUnitInfo := Project1.UnitWithEditorComponent(AEditor);
|
|
if AnUnitInfo=nil then exit;
|
|
|
|
// check if the unit is currently reverting
|
|
if AnUnitInfo.IsReverting then begin
|
|
Result:=mrOk;
|
|
exit;
|
|
end;
|
|
WasVirtual:=AnUnitInfo.IsVirtual;
|
|
WasPascalSource:=FilenameIsPascalSource(AnUnitInfo.Filename);
|
|
|
|
// check if file is writable on disk
|
|
if (not AnUnitInfo.IsVirtual)
|
|
and FileExistsUTF8(AnUnitInfo.Filename) then
|
|
AnUnitInfo.FileReadOnly:=not FileIsWritable(AnUnitInfo.Filename)
|
|
else
|
|
AnUnitInfo.FileReadOnly:=false;
|
|
|
|
// if this file is part of the project and the project is virtual then save
|
|
// project first
|
|
if (not (sfProjectSaving in Flags)) and Project1.IsVirtual
|
|
and AnUnitInfo.IsPartOfProject then
|
|
begin
|
|
SaveProjectFlags:=Flags*[sfSaveToTestDir];
|
|
if AnUnitInfo=Project1.MainUnitInfo then
|
|
Include(SaveProjectFlags,sfSaveMainSourceAs);
|
|
Result:=DoSaveProject(SaveProjectFlags);
|
|
exit;
|
|
end;
|
|
|
|
// update codetools cache and collect Modified flags
|
|
if not (sfProjectSaving in Flags) then
|
|
SaveSourceEditorChangesToCodeCache(nil);
|
|
|
|
// if this is a new unit then a simple Save becomes a SaveAs
|
|
if (not (sfSaveToTestDir in Flags)) and (AnUnitInfo.IsVirtual) then
|
|
Include(Flags,sfSaveAs);
|
|
|
|
// if this is the main source and has the same name as the lpi
|
|
// rename the project
|
|
// Note:
|
|
// Changing the main source file without the .lpi is possible only by
|
|
// manually editing the lpi file, because this is only needed in
|
|
// special cases (rare functions don't need front ends).
|
|
MainUnitInfo:=AnUnitInfo.Project.MainUnitInfo;
|
|
if (sfSaveAs in Flags) and (not (sfProjectSaving in Flags))
|
|
and (AnUnitInfo=MainUnitInfo)
|
|
then begin
|
|
Result:=DoSaveProject([sfSaveAs,sfSaveMainSourceAs]);
|
|
exit;
|
|
end;
|
|
|
|
// if file is readonly then a simple Save is skipped
|
|
if (AnUnitInfo.ReadOnly) and ([sfSaveToTestDir,sfSaveAs]*Flags=[]) then
|
|
begin
|
|
Result:=mrOk;
|
|
exit;
|
|
end;
|
|
|
|
// if nothing modified then a simple Save can be skipped
|
|
//writeln('TMainIDE.DoSaveEditorFile A ',AnUnitInfo.Filename,' ',AnUnitInfo.NeedsSaveToDisk);
|
|
if ([sfSaveToTestDir,sfSaveAs]*Flags=[])
|
|
and (not AnUnitInfo.NeedsSaveToDisk) then
|
|
begin
|
|
if AEditor.Modified then
|
|
begin
|
|
AnUnitInfo.SessionModified:=true;
|
|
AEditor.Modified:=false;
|
|
end;
|
|
Result:=mrOk;
|
|
exit;
|
|
end;
|
|
|
|
// load old resource file
|
|
LFMCode:=nil;
|
|
ResourceCode:=nil;
|
|
if WasPascalSource then
|
|
begin
|
|
Result:=DoLoadResourceFile(AnUnitInfo,LFMCode,ResourceCode,
|
|
not (sfSaveAs in Flags),true,CanAbort);
|
|
if Result in [mrIgnore,mrOk] then
|
|
Result:=mrCancel
|
|
else
|
|
exit;
|
|
end;
|
|
|
|
OldUnitName:='';
|
|
if WasPascalSource then
|
|
OldUnitName:=AnUnitInfo.ParseUnitNameFromSource(true);
|
|
OldFilename:=AnUnitInfo.Filename;
|
|
|
|
if [sfSaveAs,sfSaveToTestDir]*Flags=[sfSaveAs] then begin
|
|
// let user choose a filename
|
|
NewFilename:=OldFilename;
|
|
Result:=DoShowSaveFileAsDialog(NewFilename,AnUnitInfo,ResourceCode,CanAbort);
|
|
if Result in [mrIgnore,mrOk] then
|
|
Result:=mrCancel
|
|
else
|
|
exit;
|
|
LFMCode:=nil;
|
|
end;
|
|
|
|
// save source
|
|
|
|
// a) do before save events
|
|
if EditorOpts.AutoRemoveEmptyMethods
|
|
and (AnUnitInfo.Component<>nil) then begin
|
|
// Note: When removing published methods, the source, the lfm, the lrs
|
|
// and the form must be changed. At the moment editing the lfm without
|
|
// the component is not yet implemented.
|
|
Result:=RemoveEmptyMethods(AnUnitInfo.Source,
|
|
AnUnitInfo.Component.ClassName,0,0,false,[pcsPublished]);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
|
|
// b) do actual save
|
|
if (sfSaveToTestDir in Flags) or AnUnitInfo.IsVirtual then
|
|
begin
|
|
// save source to test directory
|
|
TestFilename := MainBuildBoss.GetTestUnitFilename(AnUnitInfo);
|
|
if TestFilename <> '' then
|
|
begin
|
|
//DebugLn(['TMainIDE.DoSaveEditorFile TestFilename="',TestFilename,'" Size=',AnUnitInfo.Source.SourceLength]);
|
|
Result := AnUnitInfo.WriteUnitSourceToFile(TestFilename);
|
|
if Result <> mrOk then
|
|
Exit;
|
|
DestFilename := TestFilename;
|
|
end
|
|
else
|
|
exit;
|
|
end else
|
|
begin
|
|
if AnUnitInfo.Modified or AnUnitInfo.NeedsSaveToDisk then
|
|
begin
|
|
// save source to file
|
|
Result := AnUnitInfo.WriteUnitSource;
|
|
if Result <> mrOK then
|
|
Exit;
|
|
DestFilename := AnUnitInfo.Filename;
|
|
end;
|
|
end;
|
|
|
|
if sfCheckAmbiguousFiles in Flags then
|
|
MainBuildBoss.CheckAmbiguousSources(DestFilename,false);
|
|
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('*** HasResources=',AnUnitInfo.HasResources);
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoSaveEditorFile B');{$ENDIF}
|
|
// save resource file and lfm file
|
|
if (ResourceCode<>nil) or (AnUnitInfo.Component<>nil) then begin
|
|
Result:=DoSaveUnitComponent(AnUnitInfo,ResourceCode,LFMCode,Flags);
|
|
if Result in [mrIgnore, mrOk] then
|
|
Result:=mrCancel
|
|
else
|
|
exit;
|
|
end;
|
|
|
|
// unset all modified flags
|
|
if not (sfSaveToTestDir in Flags) then begin
|
|
AnUnitInfo.ClearModifieds;
|
|
AEditor.Modified:=false;
|
|
UpdateSaveMenuItemsAndButtons(not (sfProjectSaving in Flags));
|
|
end;
|
|
TSourceEditor(AEditor).SourceNotebook.UpdateStatusBar;
|
|
|
|
// fix all references
|
|
NewUnitName:='';
|
|
if FilenameIsPascalSource(AnUnitInfo.Filename) then
|
|
NewUnitName:=AnUnitInfo.ParseUnitNameFromSource(true);
|
|
NewFilename:=AnUnitInfo.Filename;
|
|
if (NewUnitName<>'')
|
|
and ((OldUnitName<>NewUnitName)
|
|
or (CompareFilenames(OldFilename,NewFilename)<>0))
|
|
then begin
|
|
if EnvironmentOptions.UnitRenameReferencesAction=urraNever then
|
|
Result:=mrOK
|
|
else begin
|
|
// silently update references of new units (references were auto created
|
|
// and keeping old references makes no sense)
|
|
Confirm:=(EnvironmentOptions.UnitRenameReferencesAction=urraAsk)
|
|
and (not WasVirtual);
|
|
Result:=DoReplaceUnitUse(OldFilename,OldUnitName,NewFilename,NewUnitName,
|
|
true,true,Confirm);
|
|
end;
|
|
if Result<>mrOk then exit;
|
|
end;
|
|
|
|
{$IFDEF IDE_VERBOSE}
|
|
writeln('TMainIDE.DoSaveEditorFile END');
|
|
{$ENDIF}
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoCloseEditorFile(PageIndex:integer;
|
|
Flags: TCloseFlags): TModalResult;
|
|
begin
|
|
Result := DoCloseEditorFile(
|
|
SourceEditorManager.ActiveSourceWindow.FindSourceEditorWithPageIndex(PageIndex),
|
|
Flags);
|
|
end;
|
|
|
|
function TMainIDE.DoCloseEditorFile(const Filename: string; Flags: TCloseFlags
|
|
): TModalResult;
|
|
var
|
|
UnitIndex: Integer;
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
Result:=mrOk;
|
|
if Filename='' then exit;
|
|
UnitIndex:=Project1.IndexOfFilename(TrimFilename(Filename),
|
|
[pfsfOnlyEditorFiles]);
|
|
if UnitIndex<0 then exit;
|
|
AnUnitInfo:=Project1.Units[UnitIndex];
|
|
Result:=mrOk;
|
|
while (AnUnitInfo.OpenEditorInfoCount > 0) and (Result = mrOK) do
|
|
Result:=DoCloseEditorFile(AnUnitInfo.OpenEditorInfo[0].EditorComponent, Flags);
|
|
end;
|
|
|
|
function TMainIDE.DoCloseEditorFile(AEditor: TSourceEditorInterface;
|
|
Flags: TCloseFlags): TModalResult;
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
ACaption, AText: string;
|
|
i: integer;
|
|
AnEditorInfo: TUnitEditorInfo;
|
|
SrcEditWasFocused: Boolean;
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
{$IFDEF IDE_DEBUG}
|
|
//debugln('TMainIDE.DoCloseEditorFile A PageIndex=',IntToStr(AnUnitInfo.PageIndex));
|
|
{$ENDIF}
|
|
Result:=mrCancel;
|
|
if AEditor = nil then exit;
|
|
AnEditorInfo := Project1.EditorInfoWithEditorComponent(AEditor);
|
|
//AnUnitInfo := Project1.UnitWithEditorComponent(AEditor);
|
|
if AnEditorInfo = nil then begin
|
|
// we need to close the page anyway or else we might enter a loop
|
|
DebugLn('TMainIDE.DoCloseEditorFile INCONSISTENCY: NO AnUnitInfo');
|
|
SourceEditorManager.CloseFile(AEditor);
|
|
Result:=mrOk;
|
|
exit;
|
|
end;
|
|
AnUnitInfo := AnEditorInfo.UnitInfo;
|
|
AnUnitInfo.SessionModified:=true;
|
|
SrcEditWasFocused:=(AnEditorInfo.EditorComponent<>nil)
|
|
and (AnEditorInfo.EditorComponent.EditorControl<>nil)
|
|
and AnEditorInfo.EditorComponent.EditorControl.Focused;
|
|
//debugln(['TMainIDE.DoCloseEditorFile File=',AnUnitInfo.Filename,' WasFocused=',SrcEditWasFocused]);
|
|
try
|
|
//debugln(['TMainIDE.DoCloseEditorFile File=',AnUnitInfo.Filename,' UnitSession=',AnUnitInfo.SessionModified,' ProjSession=',project1.SessionModified]);
|
|
if AnUnitInfo.OpenEditorInfoCount > 1 then begin
|
|
// opened multiple times => close one instance
|
|
SourceEditorManager.CloseFile(AEditor);
|
|
Result:=mrOk;
|
|
exit;
|
|
end;
|
|
|
|
if (AnUnitInfo.Component<>nil)
|
|
and (FLastFormActivated<>nil)
|
|
and (TDesigner(FLastFormActivated.Designer).LookupRoot=AnUnitInfo.Component)
|
|
then
|
|
FLastFormActivated:=nil;
|
|
|
|
// save some meta data of the source
|
|
SaveSrcEditorProjectSpecificSettings(AnEditorInfo);
|
|
|
|
// if SaveFirst then save the source
|
|
if (cfSaveFirst in Flags) and (not AnUnitInfo.ReadOnly)
|
|
and ((AEditor.Modified) or (AnUnitInfo.Modified)) then begin
|
|
if not (cfQuiet in Flags) then begin
|
|
// ask user
|
|
if AnUnitInfo.Filename<>'' then
|
|
AText:=Format(lisFileHasChangedSave, ['"', AnUnitInfo.Filename, '"'])
|
|
else if AnUnitInfo.Unit_Name<>'' then
|
|
AText:=Format(lisUnitHasChangedSave, ['"', AnUnitInfo.Unit_name, '"'])
|
|
else
|
|
AText:=Format(lisSourceOfPageHasChangedSave, ['"',
|
|
TSourceEditor(AEditor).PageName, '"']);
|
|
ACaption:=lisSourceModified;
|
|
Result:=QuestionDlg(ACaption, AText,
|
|
mtConfirmation, [mrYes, lisMenuSave, mrNo, lisDiscardChanges, mrAbort
|
|
], 0);
|
|
end else
|
|
Result:=mrYes;
|
|
if Result=mrYes then begin
|
|
Result:=DoSaveEditorFile(AnEditorInfo.EditorComponent,[sfCheckAmbiguousFiles]);
|
|
end;
|
|
if Result=mrAbort then exit;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
// add to recent file list
|
|
if (not AnUnitInfo.IsVirtual)
|
|
and (not (cfProjectClosing in Flags)) then
|
|
begin
|
|
EnvironmentOptions.AddToRecentOpenFiles(AnUnitInfo.Filename);
|
|
SetRecentFilesMenu;
|
|
end;
|
|
|
|
// close form soft (keep it if used by another component)
|
|
CloseUnitComponent(AnUnitInfo,[]);
|
|
|
|
// close source editor
|
|
SourceEditorManager.CloseFile(AnEditorInfo.EditorComponent);
|
|
MainIDEBar.itmFileClose.Enabled:=SourceEditorManager.SourceEditorCount > 0;
|
|
MainIDEBar.itmFileCloseAll.Enabled:=MainIDEBar.itmFileClose.Enabled;
|
|
|
|
// free sources, forget changes
|
|
if (AnUnitInfo.Source<>nil) then begin
|
|
if (Project1.MainUnitInfo=AnUnitInfo)
|
|
and (not (cfProjectClosing in Flags)) then begin
|
|
AnUnitInfo.Source.Revert;
|
|
end else begin
|
|
AnUnitInfo.Source.IsDeleted:=true;
|
|
end;
|
|
end;
|
|
|
|
// close file in project
|
|
AnUnitInfo.Loaded:=false;
|
|
if AnUnitInfo<>Project1.MainUnitInfo then
|
|
AnUnitInfo.Source:=nil;
|
|
if not (cfProjectClosing in Flags) then begin
|
|
i:=Project1.IndexOf(AnUnitInfo);
|
|
if (i<>Project1.MainUnitID) and AnUnitInfo.IsVirtual then begin
|
|
Project1.RemoveUnit(i);
|
|
end;
|
|
end;
|
|
|
|
finally
|
|
if SrcEditWasFocused then begin
|
|
// before closing the syendit was focused. Focus the current synedit.
|
|
SrcEdit := SourceEditorManager.ActiveEditor;
|
|
if (SrcEdit<>nil)
|
|
and (SrcEdit.EditorControl<>nil)
|
|
and (SrcEdit.EditorControl.CanFocus) then
|
|
SrcEdit.EditorControl.SetFocus;
|
|
//debugln(['TMainIDE.DoCloseEditorFile Focus=',SrcEdit.FileName,' Editor=',DbgSName(SrcEdit.EditorControl),' Focused=',(SrcEdit.EditorControl<>nil) and (SrcEdit.EditorControl.Focused)]);
|
|
end;
|
|
end;
|
|
{$IFDEF IDE_DEBUG}
|
|
DebugLn('TMainIDE.DoCloseEditorFile end');
|
|
{$ENDIF}
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoOpenEditorFile(AFileName:string;
|
|
PageIndex: integer; Flags: TOpenFlags):TModalResult;
|
|
begin
|
|
Result := DoOpenEditorFile(AFileName, PageIndex,
|
|
SourceEditorManager.ActiveSourceWindowIndex, Flags);
|
|
end;
|
|
|
|
function TMainIDE.DoOpenEditorFile(AFileName: string; PageIndex,
|
|
WindowIndex: integer; Flags: TOpenFlags): TModalResult;
|
|
begin
|
|
Result := DoOpenEditorFile(AFileName, PageIndex, WindowIndex, nil, Flags);
|
|
end;
|
|
|
|
function TMainIDE.DoOpenEditorFile(AFileName: string; PageIndex,
|
|
WindowIndex: integer; AEditorInfo: TUnitEditorInfo; Flags: TOpenFlags
|
|
): TModalResult;
|
|
var
|
|
UnitIndex: integer;
|
|
ReOpen, Handled:boolean;
|
|
NewUnitInfo:TUnitInfo;
|
|
NewBuf: TCodeBuffer;
|
|
FilenameNoPath: String;
|
|
LoadBufferFlags: TLoadBufferFlags;
|
|
DiskFilename: String;
|
|
Reverting: Boolean;
|
|
CanAbort: boolean;
|
|
NewEditorInfo: TUnitEditorInfo;
|
|
|
|
function OpenResource: TModalResult;
|
|
var
|
|
CloseFlags: TCloseFlags;
|
|
begin
|
|
// read form data
|
|
if FilenameIsPascalUnit(AFilename) then begin
|
|
// this could be a unit with a form
|
|
//debugln('TMainIDE.DoOpenEditorFile ',AFilename,' ',OpenFlagsToString(Flags));
|
|
if ([ofDoNotLoadResource]*Flags=[])
|
|
and ( (ofDoLoadResource in Flags)
|
|
or ((ofProjectLoading in Flags)
|
|
and NewUnitInfo.LoadedDesigner
|
|
and (not Project1.AutoOpenDesignerFormsDisabled)
|
|
and EnvironmentOptions.AutoCreateFormsOnOpen))
|
|
then begin
|
|
// -> try to (re)load the lfm file
|
|
//debugln(['TMainIDE.DoOpenEditorFile Loading LFM for ',NewUnitInfo.Filename,' LoadedDesigner=',NewUnitInfo.LoadedDesigner]);
|
|
CloseFlags:=[cfSaveDependencies];
|
|
if ofRevert in Flags then
|
|
Include(CloseFlags,cfCloseDependencies);
|
|
Result:=DoLoadLFM(NewUnitInfo,Flags,CloseFlags);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['OpenResource DoLoadLFM failed']);
|
|
exit;
|
|
end;
|
|
end else begin
|
|
Result:=mrOk;
|
|
end;
|
|
end else if NewUnitInfo.Component<>nil then begin
|
|
// this is no pascal source and there is a designer form
|
|
// This can be the case, when the file is renamed and/or reverted
|
|
// -> close form
|
|
Result:=CloseUnitComponent(NewUnitInfo,
|
|
[cfCloseDependencies,cfSaveDependencies]);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['OpenResource CloseUnitComponent failed']);
|
|
end;
|
|
end else begin
|
|
Result:=mrOk;
|
|
end;
|
|
if NewUnitInfo.Component=nil then
|
|
NewUnitInfo.LoadedDesigner:=false;
|
|
end;
|
|
|
|
begin
|
|
{$IFDEF IDE_VERBOSE}
|
|
DebugLn('');
|
|
DebugLn(['*** TMainIDE.DoOpenEditorFile START "',AFilename,'" ',OpenFlagsToString(Flags),' Window=',WindowIndex,' Page=',PageIndex]);
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoOpenEditorFile START');{$ENDIF}
|
|
Result:=mrCancel;
|
|
|
|
CanAbort:=[ofProjectLoading,ofMultiOpen]*Flags<>[];
|
|
|
|
// replace macros
|
|
if ofConvertMacros in Flags then begin
|
|
if not GlobalMacroList.SubstituteStr(AFilename) then exit;
|
|
AFilename:=ExpandFileNameUTF8(AFilename);
|
|
end;
|
|
|
|
// revert: use source editor filename
|
|
if (ofRevert in Flags) and (PageIndex>=0) then
|
|
AFilename := SourceEditorManager.SourceEditorsByPage[WindowIndex, PageIndex].FileName;
|
|
|
|
// normalize filename
|
|
AFilename:=TrimFilename(AFilename);
|
|
DiskFilename:=FindDiskFilename(AFilename);
|
|
if DiskFilename<>AFilename then begin
|
|
// the case is different
|
|
DebugLn(['TMainIDE.DoOpenEditorFile Fixing file case: ',AFilename,' -> ',DiskFilename]);
|
|
AFilename:=DiskFilename;
|
|
end;
|
|
|
|
// check if symlink and ask user open the real file instead
|
|
ChooseSymlink(AFilename);
|
|
|
|
FilenameNoPath:=ExtractFilename(AFilename);
|
|
|
|
// check to not open directories
|
|
if ((FilenameNoPath='') or (FilenameNoPath='.') or (FilenameNoPath='..')) then
|
|
begin
|
|
DebugLn(['TMainIDE.DoOpenEditorFile ignoring special file: ',AFilename]);
|
|
exit;
|
|
end;
|
|
|
|
if ([ofAddToRecent,ofRevert,ofVirtualFile]*Flags=[ofAddToRecent])
|
|
and (AFilename<>'') and FilenameIsAbsolute(AFilename) then
|
|
EnvironmentOptions.AddToRecentOpenFiles(AFilename);
|
|
|
|
// check if this is a hidden unit:
|
|
// if this is the main unit, it is already
|
|
// loaded and needs only to be shown in the sourceeditor/formeditor
|
|
if (not (ofRevert in Flags))
|
|
and (CompareFilenames(Project1.MainFilename,AFilename,
|
|
not (ofVirtualFile in Flags))=0)
|
|
then begin
|
|
Result:=DoOpenMainUnit(PageIndex,WindowIndex,Flags);
|
|
exit;
|
|
end;
|
|
|
|
// check for special files
|
|
if ([ofRegularFile,ofRevert,ofProjectLoading]*Flags=[])
|
|
and FilenameIsAbsolute(AFilename) and FileExistsUTF8(AFilename) then begin
|
|
// check if file is a lazarus project (.lpi)
|
|
if (CompareFileExt(AFilename,'.lpi',false)=0) then begin
|
|
case
|
|
QuestionDlg(
|
|
lisOpenProject, Format(lisOpenTheProject, [AFilename]), mtConfirmation,
|
|
[mrYes, lisOpenProject2, mrNoToAll, lisOpenAsXmlFile, mrCancel], 0)
|
|
of
|
|
mrYes: begin
|
|
Result:=DoOpenProjectFile(AFilename,[ofAddToRecent]);
|
|
exit;
|
|
end;
|
|
mrNoToAll: include(Flags, ofRegularFile);
|
|
mrCancel: exit(mrCancel);
|
|
end;
|
|
|
|
end;
|
|
// check if file is a lazarus package (.lpk)
|
|
if (CompareFileExt(AFilename,'.lpk',false)=0) then begin
|
|
case
|
|
QuestionDlg(
|
|
lisOpenPackage, Format(lisOpenThePackage, [AFilename]), mtConfirmation,
|
|
[mrYes, lisCompPalOpenPackage, mrNoToAll, lisOpenAsXmlFile, mrCancel], 0)
|
|
of
|
|
mrYes: begin
|
|
Result:=PkgBoss.DoOpenPackageFile(AFilename,[pofAddToRecent],CanAbort);
|
|
exit;
|
|
end;
|
|
mrCancel: exit(mrCancel);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// check if the project knows this file
|
|
if (not (ofRevert in Flags)) then begin
|
|
UnitIndex:=Project1.IndexOfFilename(AFilename);
|
|
ReOpen:=(UnitIndex>=0);
|
|
if ReOpen then begin
|
|
NewUnitInfo:=Project1.Units[UnitIndex];
|
|
if AEditorInfo <> nil then
|
|
NewEditorInfo := AEditorInfo
|
|
else if (ofProjectLoading in Flags) then
|
|
NewEditorInfo := NewUnitInfo.GetClosedOrNewEditorInfo
|
|
else
|
|
NewEditorInfo := NewUnitInfo.EditorInfo[0];
|
|
if (ofAddToProject in Flags) and (not NewUnitInfo.IsPartOfProject) then
|
|
begin
|
|
NewUnitInfo.IsPartOfProject:=true;
|
|
Project1.Modified:=true;
|
|
end;
|
|
if (not (ofProjectLoading in Flags)) and (NewEditorInfo.EditorComponent <> nil) then
|
|
begin
|
|
//DebugLn(['TMainIDE.DoOpenEditorFile file already open ',NewUnitInfo.Filename,' WindowIndex=',NewEditorInfo.WindowIndex,' PageIndex=',NewEditorInfo.PageIndex]);
|
|
// file already open -> change source notebook page
|
|
SourceEditorManager.ActiveSourceWindowIndex := NewEditorInfo.WindowIndex;
|
|
SourceEditorManager.ActiveSourceWindow.PageIndex:= NewEditorInfo.PageIndex;
|
|
if ofDoLoadResource in Flags then
|
|
Result:=OpenResource
|
|
else
|
|
Result:=mrOk;
|
|
exit;
|
|
end;
|
|
end;
|
|
end else begin
|
|
// revert
|
|
NewEditorInfo := Project1.EditorInfoWithEditorComponent(
|
|
SourceEditorManager.SourceEditorsByPage[WindowIndex, PageIndex]);
|
|
NewUnitInfo := NewEditorInfo.UnitInfo;
|
|
UnitIndex:=Project1.IndexOf(NewUnitInfo);
|
|
AFilename:=NewUnitInfo.Filename;
|
|
if NewUnitInfo.IsVirtual then begin
|
|
if (not (ofQuiet in Flags)) then begin
|
|
MessageDlg(lisRevertFailed, Format(lisFileIsVirtual, ['"', AFilename,
|
|
'"']),
|
|
mtInformation,[mbCancel],0);
|
|
end;
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
ReOpen:=true;
|
|
if (ofAddToProject in Flags) and (not NewUnitInfo.IsPartOfProject) then
|
|
begin
|
|
NewUnitInfo.IsPartOfProject:=true;
|
|
Project1.Modified:=true;
|
|
end;
|
|
end;
|
|
|
|
Reverting:=false;
|
|
if ofRevert in Flags then begin
|
|
Reverting:=true;
|
|
Project1.BeginRevertUnit(NewUnitInfo);
|
|
end;
|
|
try
|
|
|
|
// check if file exists
|
|
if FilenameIsAbsolute(AFilename) and (not FileExistsUTF8(AFilename)) then begin
|
|
// file does not exist
|
|
if (ofRevert in Flags) then begin
|
|
// revert failed, due to missing file
|
|
if not (ofQuiet in Flags) then begin
|
|
MessageDlg(lisRevertFailed, Format(lisPkgMangFileNotFound, ['"',
|
|
AFilename, '"']),
|
|
mtError,[mbCancel],0);
|
|
end;
|
|
Result:=mrCancel;
|
|
exit;
|
|
end else begin
|
|
Result:=DoOpenNotExistingFile(AFilename,Flags);
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
// load the source
|
|
if ReOpen then begin
|
|
// project knows this file => all the meta data is known
|
|
// -> just load the source
|
|
NewUnitInfo:=Project1.Units[UnitIndex];
|
|
LoadBufferFlags:=[lbfCheckIfText];
|
|
if FilenameIsAbsolute(AFilename) then begin
|
|
if (not (ofUseCache in Flags)) then
|
|
Include(LoadBufferFlags,lbfUpdateFromDisk);
|
|
if ofRevert in Flags then
|
|
Include(LoadBufferFlags,lbfRevert);
|
|
end;
|
|
Result:=LoadCodeBuffer(NewBuf,AFileName,LoadBufferFlags,CanAbort);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TMainIDE.DoOpenEditorFile failed LoadCodeBuffer: ',AFilename]);
|
|
exit;
|
|
end;
|
|
|
|
NewUnitInfo.Source:=NewBuf;
|
|
if FilenameIsPascalUnit(NewUnitInfo.Filename) then
|
|
NewUnitInfo.ReadUnitNameFromSource(false);
|
|
NewUnitInfo.Modified:=NewUnitInfo.Source.FileOnDiskNeedsUpdate;
|
|
end else begin
|
|
// open unknown file
|
|
Handled:=false;
|
|
Result:=DoOpenUnknownFile(AFilename,Flags,NewUnitInfo,Handled);
|
|
if Result<>mrOk then exit;
|
|
// the file was previously unknown, use the default EditorInfo
|
|
if AEditorInfo <> nil then
|
|
NewEditorInfo := AEditorInfo
|
|
else
|
|
if NewUnitInfo <> nil then
|
|
NewEditorInfo := NewUnitInfo.GetClosedOrNewEditorInfo
|
|
else
|
|
NewEditorInfo := nil;
|
|
if Handled then exit;
|
|
end;
|
|
|
|
// check readonly
|
|
NewUnitInfo.FileReadOnly:=FileExistsUTF8(NewUnitInfo.Filename)
|
|
and (not FileIsWritable(NewUnitInfo.Filename));
|
|
|
|
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TMainIDE.DoOpenEditorFile] B');
|
|
{$ENDIF}
|
|
|
|
// open file in source notebook
|
|
Result:=DoOpenFileInSourceEditor(NewEditorInfo, PageIndex, WindowIndex, Flags);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TMainIDE.DoOpenEditorFile failed DoOpenFileInSourceEditor: ',AFilename]);
|
|
exit;
|
|
end;
|
|
|
|
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TMainIDE.DoOpenEditorFile] C');
|
|
{$ENDIF}
|
|
|
|
// open resource component (designer, form, datamodule, ...)
|
|
if NewUnitInfo.OpenEditorInfoCount = 1 then
|
|
Result:=OpenResource;
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TMainIDE.DoOpenEditorFile failed OpenResource: ',AFilename]);
|
|
exit;
|
|
end;
|
|
finally
|
|
if Reverting then
|
|
Project1.EndRevertUnit(NewUnitInfo);
|
|
end;
|
|
|
|
Result:=mrOk;
|
|
//writeln('TMainIDE.DoOpenEditorFile END "',AFilename,'"');
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoOpenEditorFile END');{$ENDIF}
|
|
end;
|
|
|
|
function TMainIDE.DoOpenMainUnit(PageIndex, WindowIndex: integer;
|
|
Flags: TOpenFlags): TModalResult;
|
|
var MainUnitInfo: TUnitInfo;
|
|
begin
|
|
{$IFDEF IDE_VERBOSE}
|
|
debugln(['[TMainIDE.DoOpenMainUnit] A ProjectLoading=',ofProjectLoading in Flags,' MainUnitID=',Project1.MainUnitID]);
|
|
{$ENDIF}
|
|
Result:=mrCancel;
|
|
if Project1.MainUnitID<0 then exit;
|
|
MainUnitInfo:=Project1.MainUnitInfo;
|
|
|
|
// check if main unit is already open in source editor
|
|
if (MainUnitInfo.OpenEditorInfoCount > 0) and (not (ofProjectLoading in Flags)) then
|
|
begin
|
|
// already loaded -> switch to source editor
|
|
SourceEditorManager.ActiveEditor := TSourceEditor(MainUnitInfo.OpenEditorInfo[0].EditorComponent);
|
|
SourceEditorManager.ShowActiveWindowOnTop(True);
|
|
Result:=mrOk;
|
|
exit;
|
|
end;
|
|
|
|
// open file in source notebook
|
|
Result:=DoOpenFileInSourceEditor(MainUnitInfo.GetClosedOrNewEditorInfo, PageIndex,WindowIndex,Flags);
|
|
if Result<>mrOk then exit;
|
|
|
|
Result:=mrOk;
|
|
{$IFDEF IDE_VERBOSE}
|
|
writeln('[TMainIDE.DoOpenMainUnit] END');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TMainIDE.DoRevertMainUnit: TModalResult;
|
|
begin
|
|
Result:=mrOk;
|
|
if Project1.MainUnitID<0 then exit;
|
|
if Project1.MainUnitInfo.OpenEditorInfoCount > 0 then
|
|
// main unit is loaded, so we can just revert
|
|
Result:=DoOpenEditorFile('',Project1.MainUnitInfo.EditorInfo[0].PageIndex,
|
|
Project1.MainUnitInfo.EditorInfo[0].WindowIndex, [ofRevert])
|
|
else begin
|
|
// main unit is only loaded in background
|
|
// -> just reload the source and update the source name
|
|
Result:=Project1.MainUnitInfo.ReadUnitSource(true,true);
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.SelectProjectItems(ItemList: TStringList;
|
|
ItemType: TIDEProjectItem; MultiSelect: boolean;
|
|
var MultiSelectCheckedState: Boolean): TModalResult;
|
|
var
|
|
i: integer;
|
|
AUnitName, DlgCaption: string;
|
|
MainUnitInfo: TUnitInfo;
|
|
ActiveSourceEditor: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
CurUnitInfo: TUnitInfo;
|
|
LFMFilename: String;
|
|
LFMType: String;
|
|
LFMComponentName: String;
|
|
LFMClassName: String;
|
|
anUnitName: String;
|
|
begin
|
|
GetCurrentUnit(ActiveSourceEditor, ActiveUnitInfo);
|
|
for i := 0 to Project1.UnitCount - 1 do
|
|
begin
|
|
CurUnitInfo:=Project1.Units[i];
|
|
if not CurUnitInfo.IsPartOfProject then
|
|
Continue;
|
|
if ItemType in [piComponent, piFrame] then
|
|
begin
|
|
// add all form names of project
|
|
if CurUnitInfo.ComponentName <> '' then
|
|
begin
|
|
if (ItemType = piComponent) or
|
|
((ItemType = piFrame) and (CurUnitInfo.ResourceBaseClass = pfcbcFrame)) then
|
|
ItemList.AddObject(CurUnitInfo.Unit_Name,
|
|
TViewUnitsEntry.Create(CurUnitInfo.ComponentName, i,
|
|
CurUnitInfo = ActiveUnitInfo));
|
|
end else if FilenameIsAbsolute(CurUnitInfo.Filename)
|
|
and FilenameIsPascalSource(CurUnitInfo.Filename)
|
|
and FileExistsCached(CurUnitInfo.Filename) then begin
|
|
LFMFilename:=ChangeFileExt(CurUnitInfo.Filename,'.lfm');
|
|
if FileExistsCached(LFMFilename) then begin
|
|
if ReadLFMHeaderFromFile(LFMFilename,LFMType,LFMComponentName,LFMClassName)
|
|
then begin
|
|
anUnitName:=CurUnitInfo.Unit_Name;
|
|
if anUnitName='' then
|
|
anUnitName:=ExtractFileNameOnly(LFMFilename);
|
|
ItemList.AddObject(anUnitName,
|
|
TViewUnitsEntry.Create(LFMComponentName, i,
|
|
CurUnitInfo = ActiveUnitInfo));
|
|
end;
|
|
end;
|
|
end;
|
|
end else
|
|
begin
|
|
// add all unit names of project
|
|
if (CurUnitInfo.FileName <> '') then
|
|
begin
|
|
AUnitName := ExtractFileName(CurUnitInfo.Filename);
|
|
if ItemList.IndexOf(AUnitName) = -1 then
|
|
ItemList.AddObject(AUnitName,
|
|
TViewUnitsEntry.Create(AUnitName, i, CurUnitInfo = ActiveUnitInfo));
|
|
end
|
|
else
|
|
if Project1.MainUnitID = i then
|
|
begin
|
|
MainUnitInfo := Project1.MainUnitInfo;
|
|
if pfMainUnitIsPascalSource in Project1.Flags then
|
|
begin
|
|
AUnitName := ExtractFileName(MainUnitInfo.Filename);
|
|
if (AUnitName <> '') and (ItemList.IndexOf(AUnitName) = -1) then
|
|
begin
|
|
ItemList.AddObject(AUnitName,
|
|
TViewUnitsEntry.Create(AUnitName, i, MainUnitInfo = ActiveUnitInfo));
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
case ItemType of
|
|
piUnit: begin
|
|
DlgCaption := dlgMainViewUnits;
|
|
i := IDEImages.LoadImage(16, 'item_unit');
|
|
end;
|
|
piComponent: begin
|
|
DlgCaption := dlgMainViewForms;
|
|
i := IDEImages.LoadImage(16, 'item_form');
|
|
end;
|
|
piFrame: begin
|
|
DlgCaption := dlgMainViewFrames;
|
|
i := IDEImages.LoadImage(16, 'tpanel');
|
|
end;
|
|
end;
|
|
Result := ShowViewUnitsDlg(ItemList, MultiSelect, MultiSelectCheckedState, DlgCaption, i);
|
|
end;
|
|
|
|
function TMainIDE.DoSelectFrame: TComponentClass;
|
|
var
|
|
UnitList: TStringList;
|
|
i: integer;
|
|
AnUnitInfo: TUnitInfo;
|
|
LFMCode: TCodeBuffer;
|
|
LFMFilename: String;
|
|
TheModalResult: TModalResult;
|
|
dummy: Boolean;
|
|
begin
|
|
Result := nil;
|
|
UnitList := TStringList.Create;
|
|
UnitList.Sorted := True;
|
|
try
|
|
dummy := false;
|
|
if SelectProjectItems(UnitList, piFrame, false, dummy) = mrOk then
|
|
begin
|
|
{ This is where we check what the user selected. }
|
|
AnUnitInfo := nil;
|
|
for i := 0 to UnitList.Count-1 do
|
|
begin
|
|
if TViewUnitsEntry(UnitList.Objects[i]).Selected then
|
|
begin
|
|
AnUnitInfo := Project1.Units[TViewUnitsEntry(UnitList.Objects[i]).ID];
|
|
if (AnUnitInfo.Component=nil) then begin
|
|
// load the frame
|
|
LFMFilename:=ChangeFileExt(AnUnitInfo.Filename,'.lfm');
|
|
if not FileExistsUTF8(LFMFilename) then begin
|
|
DebugLn(['TMainIDE.DoSelectFrame file not found: ',LFMFilename]);
|
|
exit;
|
|
end;
|
|
// load the lfm file
|
|
TheModalResult:=LoadCodeBuffer(LFMCode,LFMFilename,[lbfCheckIfText],false);
|
|
if TheModalResult<>mrOk then begin
|
|
debugln('TMainIDE.DoSelectFrame Failed loading ',LFMFilename);
|
|
exit;
|
|
end;
|
|
TheModalResult:=DoLoadLFM(AnUnitInfo,LFMCode,
|
|
[ofQuiet,ofOnlyIfExists,ofLoadHiddenResource],[]);
|
|
if TheModalResult<>mrOk then begin
|
|
debugln('TMainIDE.DoSelectFrame Failed streaming ',LFMFilename);
|
|
exit;
|
|
end;
|
|
end;
|
|
if (AnUnitInfo.Component<>nil) then
|
|
begin
|
|
Result := TComponentClass(AnUnitInfo.Component.ClassType);
|
|
//DebugLn(AnUnitInfo.ComponentName + ' has been selected');
|
|
break;
|
|
end;
|
|
end;
|
|
end; { for }
|
|
end; { if ShowViewUnitDlg... }
|
|
finally
|
|
for i := 0 to UnitList.Count-1 do
|
|
TViewUnitsEntry(UnitList.Objects[i]).Free;
|
|
UnitList.Free;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoViewUnitsAndForms(OnlyForms: boolean): TModalResult;
|
|
const
|
|
UseItemType: array[Boolean] of TIDEProjectItem = (piUnit, piComponent);
|
|
MultiSelectCheckedState: Array [Boolean] of Boolean = (True,True);
|
|
var
|
|
UnitList: TStringList;
|
|
i: integer;
|
|
AForm: TCustomForm;
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
UnitList := TStringList.Create;
|
|
UnitList.Sorted := True;
|
|
try
|
|
if SelectProjectItems(UnitList, UseItemType[OnlyForms],
|
|
true, MultiSelectCheckedState[OnlyForms]) = mrOk then
|
|
begin
|
|
{ This is where we check what the user selected. }
|
|
AnUnitInfo := nil;
|
|
for i := 0 to UnitList.Count-1 do
|
|
begin
|
|
if TViewUnitsEntry(UnitList.Objects[i]).Selected then
|
|
begin
|
|
AnUnitInfo := Project1.Units[TViewUnitsEntry(UnitList.Objects[i]).ID];
|
|
if AnUnitInfo.OpenEditorInfoCount > 0 then
|
|
begin
|
|
SourceEditorManager.ActiveEditor := TSourceEditor(AnUnitInfo.OpenEditorInfo[0].EditorComponent);
|
|
end else
|
|
begin
|
|
if Project1.MainUnitInfo = AnUnitInfo then
|
|
Result:=DoOpenMainUnit(-1,-1,[])
|
|
else
|
|
Result:=DoOpenEditorFile(AnUnitInfo.Filename,-1,-1,[ofOnlyIfExists]);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
if OnlyForms and (AnUnitInfo.ComponentName<>'') then
|
|
begin
|
|
AForm := GetDesignerFormOfSource(AnUnitInfo,true);
|
|
if AForm <> nil then
|
|
ShowDesignerForm(AForm);
|
|
end;
|
|
end;
|
|
end; { for }
|
|
if (AnUnitInfo <> nil) and (not OnlyForms) then
|
|
begin
|
|
SourceEditorManager.ShowActiveWindowOnTop(False);
|
|
end;
|
|
end; { if ShowViewUnitDlg... }
|
|
finally
|
|
for i := 0 to UnitList.Count-1 do
|
|
TViewUnitsEntry(UnitList.Objects[i]).Free;
|
|
UnitList.Free;
|
|
end;
|
|
Result := mrOk;
|
|
end;
|
|
|
|
procedure TMainIDE.DoViewUnitDependencies(Show: boolean);
|
|
begin
|
|
if UnitDependenciesView=nil then begin
|
|
UnitDependenciesView:=TUnitDependenciesView.Create(OwningComponent);
|
|
UnitDependenciesView.OnAccessingSources:=
|
|
@UnitDependenciesViewAccessingSources;
|
|
UnitDependenciesView.OnGetProjectMainFilename:=
|
|
@UnitDependenciesViewGetProjectMainFilename;
|
|
UnitDependenciesView.OnOpenFile:=@UnitDependenciesViewOpenFile;
|
|
end;
|
|
|
|
if not UnitDependenciesView.RootValid then begin
|
|
if Project1.MainUnitID>=0 then begin
|
|
UnitDependenciesView.BeginUpdate;
|
|
UnitDependenciesView.RootFilename:=Project1.MainUnitInfo.Filename;
|
|
UnitDependenciesView.RootShortFilename:=
|
|
ExtractFilename(Project1.MainUnitInfo.Filename);
|
|
UnitDependenciesView.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
if Show then
|
|
IDEWindowCreators.ShowForm(UnitDependenciesView,true);
|
|
end;
|
|
|
|
procedure TMainIDE.DoViewJumpHistory(Show: boolean);
|
|
begin
|
|
if JumpHistoryViewWin=nil then begin
|
|
JumpHistoryViewWin:=TJumpHistoryViewWin.Create(OwningComponent);
|
|
with JumpHistoryViewWin do begin
|
|
OnSelectionChanged := @JumpHistoryViewSelectionChanged;
|
|
end;
|
|
end;
|
|
if Show then
|
|
IDEWindowCreators.ShowForm(JumpHistoryViewWin,true);
|
|
end;
|
|
|
|
procedure TMainIDE.DoViewUnitInfo;
|
|
var ActiveSrcEdit:TSourceEditor;
|
|
ActiveUnitInfo:TUnitInfo;
|
|
ShortUnitName, AFilename, FileDir: string;
|
|
ClearIncludedByFile: boolean;
|
|
DlgResult: TModalResult;
|
|
SizeInBytes: Integer;
|
|
UnitSizeWithIncludeFiles: integer;
|
|
UnitSizeParsed: integer;
|
|
LineCount: LongInt;
|
|
UnitLineCountWithIncludes: LongInt;
|
|
UnitLineCountParsed: LongInt;
|
|
Code: TCodeBuffer;
|
|
CTTool: TCodeTool;
|
|
TreeOfSourceCodes: TAVLTree;
|
|
Node: TAVLTreeNode;
|
|
SubCode: TCodeBuffer;
|
|
begin
|
|
GetCurrentUnit(ActiveSrcEdit,ActiveUnitInfo);
|
|
if (ActiveSrcEdit=nil) or (ActiveUnitInfo=nil) then exit;
|
|
ShortUnitName:=ActiveSrcEdit.PageName;
|
|
AFilename:=ActiveUnitInfo.Filename;
|
|
FileDir:=ExtractFilePath(AFilename);
|
|
|
|
SizeInBytes:=length(ActiveSrcEdit.Source.Text);
|
|
UnitSizeWithIncludeFiles:=SizeInBytes;
|
|
UnitSizeParsed:=SizeInBytes;
|
|
LineCount:=ActiveSrcEdit.Source.Count;
|
|
UnitLineCountWithIncludes:=LineCount;
|
|
UnitLineCountParsed:=LineCount;
|
|
|
|
// check size of parsed source (without skipped code due to $ELSE)
|
|
// and total size of all include files
|
|
Code:=ActiveSrcEdit.CodeBuffer;
|
|
if Code<>nil then
|
|
begin
|
|
CodeToolBoss.Explore(ActiveSrcEdit.CodeBuffer,CTTool,false,false);
|
|
if CTTool<>nil then
|
|
begin
|
|
UnitSizeParsed:=CTTool.SrcLen;
|
|
UnitLineCountParsed:=LineEndCount(CTTool.Src);
|
|
if CTTool.Scanner<>nil then
|
|
begin
|
|
TreeOfSourceCodes:=CTTool.Scanner.CreateTreeOfSourceCodes;
|
|
if TreeOfSourceCodes<>nil then
|
|
begin
|
|
UnitSizeWithIncludeFiles:=0;
|
|
UnitLineCountWithIncludes:=0;
|
|
Node:=TreeOfSourceCodes.FindLowest;
|
|
while Node<>nil do begin
|
|
SubCode:=TCodeBuffer(Node.Data);
|
|
inc(UnitSizeWithIncludeFiles,SubCode.SourceLength);
|
|
inc(UnitLineCountWithIncludes,SubCode.LineCount);
|
|
Node:=TreeOfSourceCodes.FindSuccessor(Node);
|
|
end;
|
|
TreeOfSourceCodes.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
DlgResult:=ShowUnitInfoDlg(ShortUnitName,
|
|
LazSyntaxHighlighterNames[ActiveUnitInfo.DefaultSyntaxHighlighter],
|
|
ActiveUnitInfo.IsPartOfProject,
|
|
SizeInBytes,UnitSizeWithIncludeFiles,UnitSizeParsed,
|
|
LineCount,UnitLineCountWithIncludes,UnitLineCountParsed,
|
|
AFilename,
|
|
ActiveUnitInfo.Source.LastIncludedByFile,
|
|
ClearIncludedByFile,
|
|
TrimSearchPath(CodeToolBoss.GetUnitPathForDirectory(FileDir),FileDir),
|
|
TrimSearchPath(CodeToolBoss.GetIncludePathForDirectory(FileDir),FileDir),
|
|
TrimSearchPath(CodeToolBoss.GetCompleteSrcPathForDirectory(FileDir),FileDir)
|
|
);
|
|
if ClearIncludedByFile then
|
|
ActiveUnitInfo.Source.LastIncludedByFile:='';
|
|
if (DlgResult=mrYes) and (ActiveUnitInfo.Source.LastIncludedByFile<>'') then
|
|
DoGotoIncludeDirective;
|
|
end;
|
|
|
|
procedure TMainIDE.DoShowCodeExplorer(Show: boolean);
|
|
begin
|
|
if CodeExplorerView=nil then
|
|
begin
|
|
CodeExplorerView:=TCodeExplorerView.Create(OwningComponent);
|
|
CodeExplorerView.OnGetDirectivesTree:=@OnCodeExplorerGetDirectivesTree;
|
|
CodeExplorerView.OnJumpToCode:=@OnCodeExplorerJumpToCode;
|
|
CodeExplorerView.OnShowOptions:=@OnCodeExplorerShowOptions;
|
|
end;
|
|
|
|
if Show then
|
|
begin
|
|
IDEWindowCreators.ShowForm(CodeExplorerView,true);
|
|
CodeExplorerView.Refresh(true);
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.DoShowCodeBrowser(Show: boolean);
|
|
begin
|
|
CreateCodeBrowser;
|
|
if Show then
|
|
IDEWindowCreators.ShowForm(CodeBrowserView,true);
|
|
end;
|
|
|
|
procedure TMainIDE.DoShowRestrictionBrowser(Show: boolean;
|
|
const RestrictedName: String);
|
|
begin
|
|
if RestrictionBrowserView = nil then
|
|
RestrictionBrowserView := TRestrictionBrowserView.Create(OwningComponent);
|
|
|
|
RestrictionBrowserView.SetIssueName(RestrictedName);
|
|
if Show then
|
|
IDEWindowCreators.ShowForm(RestrictionBrowserView,true);
|
|
end;
|
|
|
|
procedure TMainIDE.DoShowComponentList(Show: boolean);
|
|
begin
|
|
if not Assigned(ComponentListForm) then
|
|
begin
|
|
ComponentListForm := TComponentListForm.Create(OwningComponent);
|
|
ComponentListForm.Name:=ComponentListFormName;
|
|
end;
|
|
if Show then
|
|
ComponentListForm.Show;
|
|
end;
|
|
|
|
procedure TMainIDE.CreateIDEWindow(Sender: TObject; aFormName: string; var
|
|
AForm: TCustomForm; DoDisableAutoSizing: boolean);
|
|
|
|
function ItIs(Prefix: string): boolean;
|
|
begin
|
|
Result:=SysUtils.CompareText(copy(aFormName,1,length(Prefix)),Prefix)=0;
|
|
end;
|
|
|
|
begin
|
|
if ItIs(NonModalIDEWindowNames[nmiwMessagesViewName]) then
|
|
AForm:=MessagesView
|
|
else if ItIs(NonModalIDEWindowNames[nmiwUnitDependenciesName]) then
|
|
begin
|
|
DoViewUnitDependencies(false);
|
|
AForm:=UnitDependenciesView;
|
|
end
|
|
else if ItIs(NonModalIDEWindowNames[nmiwCodeExplorerName]) then
|
|
begin
|
|
DoShowCodeExplorer(false);
|
|
AForm:=CodeExplorerView;
|
|
end
|
|
else if ItIs(NonModalIDEWindowNames[nmiwFPDocEditorName]) then
|
|
begin
|
|
DoShowFPDocEditor(false,false);
|
|
AForm:=FPDocEditor;
|
|
end
|
|
// ToDo: nmiwClipbrdHistoryName:
|
|
else if ItIs(NonModalIDEWindowNames[nmiwProjectInspector]) then
|
|
begin
|
|
DoShowProjectInspector(false);
|
|
AForm:=ProjInspector;
|
|
end
|
|
else if ItIs(NonModalIDEWindowNames[nmiwSearchResultsViewName]) then
|
|
begin
|
|
DoShowSearchResultsView(false,false);
|
|
AForm:=SearchResultsView;
|
|
end
|
|
else if ItIs(NonModalIDEWindowNames[nmiwAnchorEditor]) then
|
|
begin
|
|
DoViewAnchorEditor(false);
|
|
AForm:=AnchorDesigner;
|
|
end
|
|
else if ItIs(NonModalIDEWindowNames[nmiwTabOrderEditor]) then
|
|
begin
|
|
DoViewTabOrderEditor(false);
|
|
AForm:=TabOrderDialog;
|
|
end
|
|
else if ItIs(NonModalIDEWindowNames[nmiwCodeBrowser]) then
|
|
begin
|
|
DoShowCodeBrowser(false);
|
|
AForm:=CodeBrowserView;
|
|
end
|
|
else if ItIs(NonModalIDEWindowNames[nmiwIssueBrowser]) then
|
|
begin
|
|
DoShowRestrictionBrowser(false);
|
|
AForm:=RestrictionBrowserView;
|
|
end
|
|
else if ItIs(NonModalIDEWindowNames[nmiwJumpHistory]) then
|
|
begin
|
|
DoViewJumpHistory(false);
|
|
AForm:=JumpHistoryViewWin;
|
|
end
|
|
else if ItIs(ComponentListFormName) then
|
|
begin
|
|
DoShowComponentList(false);
|
|
AForm:=ComponentListForm;
|
|
end;
|
|
if (AForm<>nil) and DoDisableAutoSizing then
|
|
AForm.DisableAutoSizing;
|
|
end;
|
|
|
|
function TMainIDE.CreateNewUniqueFilename(const Prefix, Ext: string;
|
|
NewOwner: TObject; Flags: TSearchIDEFileFlags; TryWithoutNumber: boolean): string;
|
|
|
|
function FileIsUnique(const ShortFilename: string): boolean;
|
|
begin
|
|
Result:=false;
|
|
|
|
// search in NewOwner
|
|
if NewOwner<>nil then begin
|
|
if (NewOwner is TProject) then begin
|
|
if TProject(NewOwner).SearchFile(ShortFilename,Flags)<>nil then exit;
|
|
end;
|
|
end;
|
|
|
|
// search in all packages
|
|
if PkgBoss.SearchFile(ShortFilename,Flags,NewOwner)<>nil then exit;
|
|
|
|
// search in current project
|
|
if (NewOwner<>Project1)
|
|
and (Project1.SearchFile(ShortFilename,Flags)<>nil) then exit;
|
|
|
|
// search file in all loaded projects
|
|
if (siffCheckAllProjects in Flags) then begin
|
|
end;
|
|
|
|
Result:=true;
|
|
end;
|
|
|
|
var
|
|
i: Integer;
|
|
WorkingPrefix: String;
|
|
begin
|
|
if TryWithoutNumber then begin
|
|
Result:=Prefix+Ext;
|
|
if FileIsUnique(Result) then exit;
|
|
end;
|
|
// remove number at end of Prefix
|
|
WorkingPrefix:=ChompEndNumber(Prefix);
|
|
i:=0;
|
|
repeat
|
|
inc(i);
|
|
Result:=WorkingPrefix+IntToStr(i)+Ext;
|
|
until FileIsUnique(Result);
|
|
end;
|
|
|
|
procedure TMainIDE.MarkUnitsModifiedUsingSubComponent(SubComponent: TComponent);
|
|
var
|
|
UnitList: TFPList;
|
|
i: Integer;
|
|
AnUnitInfo: TUnitInfo;
|
|
ADesigner: TDesigner;
|
|
begin
|
|
UnitList:=TFPList.Create;
|
|
Project1.FindUnitsUsingSubComponent(SubComponent,UnitList,true);
|
|
for i:=0 to UnitList.Count-1 do begin
|
|
AnUnitInfo:=TUnitInfo(UnitList[i]);
|
|
if (AnUnitInfo.Component<>nil) then begin
|
|
ADesigner:=TDesigner(FindRootDesigner(AnUnitInfo.Component));
|
|
{$IFDEF VerboseIDEMultiForm}
|
|
DebugLn(['TMainIDE.MarkUnitsModifiedUsingSubComponent ',AnUnitInfo.Filename,' ',dbgsName(ADesigner)]);
|
|
{$ENDIF}
|
|
if ADesigner is TDesigner then
|
|
ADesigner.Modified;
|
|
end;
|
|
end;
|
|
UnitList.Free;
|
|
end;
|
|
|
|
function TMainIDE.GetAvailableUnitEditorInfo(AnUnitInfo: TUnitInfo;
|
|
ACaretPoint: TPoint; WantedTopLine: integer = -1): TUnitEditorInfo;
|
|
|
|
function EditorMatches(AEditInfo: TUnitEditorInfo;
|
|
AAccess: TEditorOptionsEditAccessOrderEntry; ALockRun: Integer = 0): Boolean;
|
|
var
|
|
AEdit: TSourceEditor;
|
|
begin
|
|
AEdit := TSourceEditor(AEditInfo.EditorComponent);
|
|
Result := False;
|
|
case AAccess.SearchLocked of
|
|
eoeaIgnoreLock: ;
|
|
eoeaLockedOnly: if not AEdit.IsLocked then exit;
|
|
eoeaUnlockedOnly: if AEdit.IsLocked then exit;
|
|
eoeaLockedFirst: if (not AEdit.IsLocked) and (ALockRun = 0) then exit;
|
|
eoeaLockedLast: if (AEdit.IsLocked) and (ALockRun = 0) then exit;
|
|
end;
|
|
case AAccess.SearchInView of
|
|
eoeaIgnoreInView: ;
|
|
eoeaInViewOnly: if not AEdit.IsCaretOnScreen(ACaretPoint, False) then exit;
|
|
eoeaInViewSoftCenterOnly: if not AEdit.IsCaretOnScreen(ACaretPoint, True) then exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function AvailSrcWindowIndex: Integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := -1;
|
|
i := 0;
|
|
if AnUnitInfo.OpenEditorInfoCount > 0 then
|
|
while (i < SourceEditorManager.SourceWindowCount) and
|
|
(SourceEditorManager.SourceWindowByLastFocused[i].IndexOfEditorInShareWith
|
|
(TSourceEditor(AnUnitInfo.OpenEditorInfo[0].EditorComponent)) >= 0)
|
|
do
|
|
inc(i);
|
|
if i < SourceEditorManager.SourceWindowCount then
|
|
Result := SourceEditorManager.IndexOfSourceWindow(SourceEditorManager.SourceWindowByLastFocused[i]);
|
|
end;
|
|
|
|
var
|
|
i, j, w, LockRun: Integer;
|
|
Access: TEditorOptionsEditAccessOrderEntry;
|
|
begin
|
|
Result := nil;
|
|
if AnUnitInfo.OpenEditorInfoCount = 0 then exit;
|
|
for i := 0 to EditorOpts.MultiWinEditAccessOrder.Count - 1 do begin
|
|
Access := EditorOpts.MultiWinEditAccessOrder[i];
|
|
if not Access.Enabled then continue;
|
|
LockRun := 1;
|
|
if Access.SearchLocked in [eoeaLockedFirst, eoeaLockedLast] then LockRun := 0;
|
|
repeat
|
|
case Access.RealSearchOrder of
|
|
eoeaOrderByEditFocus, eoeaOrderByListPref:
|
|
begin
|
|
for j := 0 to AnUnitInfo.OpenEditorInfoCount - 1 do
|
|
if EditorMatches(AnUnitInfo.OpenEditorInfo[j], Access) then begin
|
|
Result := AnUnitInfo.OpenEditorInfo[j];
|
|
break;
|
|
end;
|
|
end;
|
|
eoeaOrderByWindowFocus:
|
|
begin
|
|
for w := 0 to SourceEditorManager.SourceWindowCount - 1 do begin
|
|
for j := 0 to AnUnitInfo.OpenEditorInfoCount - 1 do
|
|
if (TSourceEditor(AnUnitInfo.OpenEditorInfo[j].EditorComponent).SourceNotebook
|
|
= SourceEditorManager.SourceWindowByLastFocused[w])
|
|
and EditorMatches(AnUnitInfo.OpenEditorInfo[j], Access) then begin
|
|
Result := AnUnitInfo.OpenEditorInfo[j];
|
|
break;
|
|
end;
|
|
if Result <> nil then break;
|
|
end;
|
|
end;
|
|
eoeaOrderByOldestEditFocus:
|
|
begin
|
|
for j := AnUnitInfo.OpenEditorInfoCount - 1 downto 0 do
|
|
if EditorMatches(AnUnitInfo.OpenEditorInfo[j], Access) then begin
|
|
Result := AnUnitInfo.OpenEditorInfo[j];
|
|
break;
|
|
end;
|
|
end;
|
|
eoeaOrderByOldestWindowFocus:
|
|
begin
|
|
for w := SourceEditorManager.SourceWindowCount - 1 downto 0 do begin
|
|
for j := 0 to AnUnitInfo.OpenEditorInfoCount - 1 do
|
|
if (TSourceEditor(AnUnitInfo.OpenEditorInfo[j].EditorComponent).SourceNotebook
|
|
= SourceEditorManager.SourceWindowByLastFocused[w])
|
|
and EditorMatches(AnUnitInfo.OpenEditorInfo[j], Access) then begin
|
|
Result := AnUnitInfo.OpenEditorInfo[j];
|
|
break;
|
|
end;
|
|
if Result <> nil then break;
|
|
end;
|
|
end;
|
|
eoeaOnlyCurrentEdit:
|
|
begin
|
|
LockRun := 1;
|
|
for j := 0 to AnUnitInfo.OpenEditorInfoCount - 1 do
|
|
if (AnUnitInfo.OpenEditorInfo[j].EditorComponent = SourceEditorManager.ActiveEditor)
|
|
and EditorMatches(AnUnitInfo.OpenEditorInfo[j], Access) then begin
|
|
Result := AnUnitInfo.OpenEditorInfo[j];
|
|
break;
|
|
end;
|
|
end;
|
|
eoeaOnlyCurrentWindow:
|
|
begin
|
|
LockRun := 1;
|
|
for j := 0 to AnUnitInfo.OpenEditorInfoCount - 1 do
|
|
if (TSourceEditor(AnUnitInfo.OpenEditorInfo[j].EditorComponent).SourceNotebook
|
|
= SourceEditorManager.ActiveSourceWindow)
|
|
and EditorMatches(AnUnitInfo.OpenEditorInfo[j], Access) then begin
|
|
Result := AnUnitInfo.OpenEditorInfo[j];
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
inc(LockRun);
|
|
until (LockRun > 1) or (Result <> nil);
|
|
if (Result = nil) then
|
|
case Access.SearchOpenNew of
|
|
eoeaNoNewTab: ;
|
|
eoeaNewTabInExistingWindowOnly:
|
|
begin
|
|
w := AvailSrcWindowIndex;
|
|
if w >= 0 then
|
|
if DoOpenFileInSourceEditor(AnUnitInfo.GetClosedOrNewEditorInfo, -1, w, []) = mrOk then
|
|
Result := AnUnitInfo.OpenEditorInfo[0]; // newly opened will be last focused
|
|
end;
|
|
eoeaNewTabInNewWindowOnly:
|
|
begin
|
|
if DoOpenFileInSourceEditor(AnUnitInfo.GetClosedOrNewEditorInfo,
|
|
-1, SourceEditorManager.SourceWindowCount, []) = mrOk
|
|
then
|
|
Result := AnUnitInfo.OpenEditorInfo[0]; // newly opened will be last focused
|
|
end;
|
|
eoeaNewTabInExistingOrNewWindow:
|
|
begin
|
|
w := AvailSrcWindowIndex;
|
|
if w < 0 then w := SourceEditorManager.SourceWindowCount;
|
|
if DoOpenFileInSourceEditor(AnUnitInfo.GetClosedOrNewEditorInfo, -1, w, []) = mrOk then
|
|
Result := AnUnitInfo.OpenEditorInfo[0]; // newly opened will be last focused
|
|
end;
|
|
end;
|
|
if Result <> nil then
|
|
break;
|
|
end;
|
|
if Result = nil then // should never happen
|
|
Result := AnUnitInfo.OpenEditorInfo[0];
|
|
end;
|
|
|
|
function TMainIDE.LoadIDECodeBuffer(var ACodeBuffer: TCodeBuffer;
|
|
const AFilename: string; Flags: TLoadBufferFlags; ShowAbort: boolean
|
|
): TModalResult;
|
|
begin
|
|
if Project1.UnitInfoWithFilename(AFilename,[pfsfOnlyEditorFiles])<>nil then
|
|
Exclude(Flags,lbfUpdateFromDisk);
|
|
Result:=LoadCodeBuffer(ACodeBuffer,AFilename,Flags,ShowAbort);
|
|
end;
|
|
|
|
function TMainIDE.DoOpenFileAtCursor(Sender: TObject):TModalResult;
|
|
var ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
FName,SPath: String;
|
|
|
|
function FindFile(var FName: String; SPath: String): Boolean;
|
|
// Searches for FName in SPath
|
|
// If FName is not found, we'll check extensions pp and pas too
|
|
// Returns true if found. FName contains the full file+path in that case
|
|
var TempFile,TempPath,CurPath,FinalFile, Ext: String;
|
|
p,c: Integer;
|
|
PasExt: TPascalExtType;
|
|
begin
|
|
if SPath='' then SPath:='.';
|
|
Result:=true;
|
|
TempPath:=SPath;
|
|
while TempPath<>'' do begin
|
|
p:=pos(';',TempPath);
|
|
if p=0 then p:=length(TempPath)+1;
|
|
CurPath:=copy(TempPath,1,p-1);
|
|
Delete(TempPath,1,p);
|
|
if CurPath='' then continue;
|
|
CurPath:=AppendPathDelim(CurPath);
|
|
if not FilenameIsAbsolute(CurPath) then begin
|
|
if ActiveUnitInfo.IsVirtual then
|
|
CurPath:=AppendPathDelim(Project1.ProjectDirectory)+CurPath
|
|
else
|
|
CurPath:=AppendPathDelim(ExtractFilePath(ActiveUnitInfo.Filename))
|
|
+CurPath;
|
|
end;
|
|
for c:=0 to 2 do begin
|
|
// FPC searches first lowercase, then keeping case, then uppercase
|
|
case c of
|
|
0: TempFile:=LowerCase(FName);
|
|
1: TempFile:=FName;
|
|
2: TempFile:=UpperCase(FName);
|
|
end;
|
|
if ExtractFileExt(TempFile)='' then begin
|
|
for PasExt:=Low(TPascalExtType) to High(TPascalExtType) do begin
|
|
Ext:=PascalExtension[PasExt];
|
|
FinalFile:=ExpandFileNameUTF8(CurPath+TempFile+Ext);
|
|
if FileExistsUTF8(FinalFile) then begin
|
|
FName:=FinalFile;
|
|
exit;
|
|
end;
|
|
end;
|
|
end else begin
|
|
FinalFile:=ExpandFileNameUTF8(CurPath+TempFile);
|
|
if FileExistsUTF8(FinalFile) then begin
|
|
FName:=FinalFile;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
Result:=false;
|
|
end;
|
|
|
|
function CheckIfIncludeDirectiveInFront(const Line: string;
|
|
X: integer): boolean;
|
|
var
|
|
DirectiveEnd, DirectiveStart: integer;
|
|
Directive: string;
|
|
begin
|
|
Result:=false;
|
|
DirectiveEnd:=X;
|
|
while (DirectiveEnd>1) and (Line[DirectiveEnd-1] in [' ',#9]) do
|
|
dec(DirectiveEnd);
|
|
DirectiveStart:=DirectiveEnd-1;
|
|
while (DirectiveStart>0) and (Line[DirectiveStart]<>'$') do
|
|
dec(DirectiveStart);
|
|
Directive:=uppercase(copy(Line,DirectiveStart,DirectiveEnd-DirectiveStart));
|
|
if (Directive='$INCLUDE') or (Directive='$I') then begin
|
|
if ((DirectiveStart>1) and (Line[DirectiveStart-1]='{'))
|
|
or ((DirectiveStart>2)
|
|
and (Line[DirectiveStart-2]='(') and (Line[DirectiveStart-1]='*'))
|
|
then begin
|
|
Result:=true;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function GetFilenameAtRowCol(XY: TPoint;
|
|
var IsIncludeDirective: boolean): string;
|
|
var
|
|
Line: string;
|
|
Len, Stop: integer;
|
|
StopChars: set of char;
|
|
begin
|
|
Result := '';
|
|
IsIncludeDirective:=false;
|
|
if (XY.Y >= 1) and (XY.Y <= ActiveSrcEdit.EditorComponent.Lines.Count) then
|
|
begin
|
|
Line := ActiveSrcEdit.EditorComponent.Lines.Strings[XY.Y - 1];
|
|
Len := Length(Line);
|
|
if (XY.X >= 1) and (XY.X <= Len + 1) then begin
|
|
StopChars := [',',';',':','[',']','{','}','(',')',' ','''','"','`'
|
|
,'#','%','=','>'];
|
|
Stop := XY.X;
|
|
while (Stop <= Len) and (not (Line[Stop] in StopChars)) do
|
|
Inc(Stop);
|
|
while (XY.X > 1) and (not (Line[XY.X - 1] in StopChars)) do
|
|
Dec(XY.X);
|
|
if Stop > XY.X then begin
|
|
Result := Copy(Line, XY.X, Stop - XY.X);
|
|
IsIncludeDirective:=CheckIfIncludeDirectiveInFront(Line,XY.X);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
IsIncludeDirective: boolean;
|
|
BaseDir: String;
|
|
NewFilename: string;
|
|
Found: Boolean;
|
|
AUnitName: String;
|
|
InFilename: String;
|
|
begin
|
|
Result:=mrCancel;
|
|
GetCurrentUnit(ActiveSrcEdit,ActiveUnitInfo);
|
|
if (ActiveSrcEdit=nil) or (ActiveUnitInfo=nil) then exit;
|
|
BaseDir:=ExtractFilePath(ActiveUnitInfo.Filename);
|
|
|
|
// parse filename at cursor
|
|
IsIncludeDirective:=false;
|
|
Found:=false;
|
|
FName:=GetFilenameAtRowCol(ActiveSrcEdit.EditorComponent.LogicalCaretXY,
|
|
IsIncludeDirective);
|
|
if FName='' then exit;
|
|
|
|
// check if absolute filename
|
|
if FilenameIsAbsolute(FName) and FileExistsUTF8(FName) then
|
|
Found:=true;
|
|
|
|
if (not Found) and (not FilenameIsAbsolute(FName)) then begin
|
|
if IsIncludeDirective then begin
|
|
// search include file
|
|
SPath:='.;'+CodeToolBoss.DefineTree.GetIncludePathForDirectory(BaseDir);
|
|
if FindFile(FName,SPath) then
|
|
Found:=true;
|
|
end else if FilenameIsPascalSource(FName) or (ExtractFileExt(FName)='') then
|
|
begin
|
|
// search pascal unit
|
|
AUnitName:=ExtractFileNameOnly(FName);
|
|
InFilename:=FName;
|
|
if ExtractFileExt(FName)='' then InFilename:='';
|
|
NewFilename:=CodeToolBoss.DirectoryCachePool.FindUnitSourceInCompletePath(
|
|
BaseDir,AUnitName,InFilename,true);
|
|
if NewFilename<>'' then begin
|
|
Found:=true;
|
|
FName:=NewFilename;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if (not Found) and (System.Pos('.',FName)>0) and (not IsIncludeDirective) then
|
|
begin
|
|
// for example 'SysUtils.CompareText'
|
|
FName:=ActiveSrcEdit.EditorComponent.GetWordAtRowCol(
|
|
ActiveSrcEdit.EditorComponent.LogicalCaretXY);
|
|
if (FName<>'') and IsValidIdent(FName) then begin
|
|
// search pascal unit
|
|
AUnitName:=FName;
|
|
InFilename:='';
|
|
NewFilename:=CodeToolBoss.DirectoryCachePool.FindUnitSourceInCompletePath(
|
|
BaseDir,AUnitName,InFilename,true);
|
|
if NewFilename<>'' then begin
|
|
Found:=true;
|
|
FName:=NewFilename;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if Found then begin
|
|
// open
|
|
InputHistories.SetFileDialogSettingsInitialDir(ExtractFilePath(FName));
|
|
Result:=DoOpenEditorFile(FName,-1,-1,[ofAddToRecent]);
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoOpenFileAndJumpToIdentifier(const AFilename,
|
|
AnIdentifier: string; PageIndex: integer; Flags: TOpenFlags): TModalResult;
|
|
begin
|
|
Result := DoOpenFileAndJumpToIdentifier(AFilename, AnIdentifier, PageIndex,
|
|
SourceEditorManager.ActiveSourceWindowIndex, Flags);
|
|
end;
|
|
|
|
function TMainIDE.DoOpenFileAndJumpToIdentifier(const AFilename,
|
|
AnIdentifier: string; PageIndex, WindowIndex: integer; Flags: TOpenFlags
|
|
): TModalResult;
|
|
var
|
|
ActiveUnitInfo: TUnitInfo;
|
|
ActiveSrcEdit: TSourceEditor;
|
|
NewSource: TCodeBuffer;
|
|
NewX, NewY, NewTopLine: integer;
|
|
begin
|
|
Result:=DoOpenEditorFile(AFilename, PageIndex, WindowIndex, Flags);
|
|
if Result<>mrOk then exit;
|
|
Result:=mrCancel;
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
if CodeToolBoss.FindDeclarationInInterface(ActiveUnitInfo.Source,
|
|
AnIdentifier,NewSource, NewX, NewY, NewTopLine)
|
|
then begin
|
|
DoJumpToCodePosition(ActiveSrcEdit, ActiveUnitInfo,
|
|
NewSource, NewX, NewY, NewTopLine, [jfAddJumpPoint, jfFocusEditor]);
|
|
Result:=mrOk;
|
|
end else
|
|
DoJumpToCodeToolBossError;
|
|
end;
|
|
|
|
function TMainIDE.DoOpenFileAndJumpToPos(const AFilename: string;
|
|
const CursorPosition: TPoint; TopLine: integer; PageIndex: integer;
|
|
Flags: TOpenFlags): TModalResult;
|
|
begin
|
|
Result := DoOpenFileAndJumpToPos(AFilename, CursorPosition, TopLine, PageIndex,
|
|
SourceEditorManager.ActiveSourceWindowIndex, Flags);
|
|
end;
|
|
|
|
function TMainIDE.DoOpenFileAndJumpToPos(const AFilename: string;
|
|
const CursorPosition: TPoint; TopLine: integer; PageIndex,
|
|
WindowIndex: integer; Flags: TOpenFlags): TModalResult;
|
|
var
|
|
ActiveUnitInfo, OldActiveUnitInfo: TUnitInfo;
|
|
ActiveSrcEdit, OldActiveSrcEdit: TSourceEditor;
|
|
begin
|
|
GetCurrentUnit(OldActiveSrcEdit,OldActiveUnitInfo);
|
|
Result:=DoOpenEditorFile(AFilename, PageIndex, WindowIndex, Flags);
|
|
if Result<>mrOk then exit;
|
|
GetCurrentUnit(ActiveSrcEdit,ActiveUnitInfo);
|
|
if ActiveUnitInfo<>nil then begin
|
|
DoJumpToCodePosition(OldActiveSrcEdit, OldActiveUnitInfo,
|
|
ActiveUnitInfo.Source,
|
|
CursorPosition.X, CursorPosition.Y, TopLine, [jfAddJumpPoint, jfFocusEditor]);
|
|
Result:=mrOk;
|
|
end else begin
|
|
Result:=mrCancel;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoRevertEditorFile(const Filename: string): TModalResult;
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
Result:=mrCancel;
|
|
if (Project1<>nil) then begin
|
|
AnUnitInfo:=Project1.UnitInfoWithFilename(Filename,[]);
|
|
if (AnUnitInfo<>nil) and (AnUnitInfo.OpenEditorInfoCount > 0) then
|
|
Result:=DoOpenEditorFile(AnUnitInfo.Filename,
|
|
AnUnitInfo.OpenEditorInfo[0].PageIndex,
|
|
AnUnitInfo.OpenEditorInfo[0].WindowIndex,
|
|
[ofRevert]); // Reverting one will revert all
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.DoLoadDefaultCompilerOptions(AProject: TProject);
|
|
var
|
|
AFilename: String;
|
|
begin
|
|
// load default compiler options if exists
|
|
AFilename:=AppendPathDelim(GetPrimaryConfigPath)+DefaultProjectCompilerOptionsFilename;
|
|
if not FileExistsUTF8(AFilename) then
|
|
CopySecondaryConfigFile(DefaultProjectCompilerOptionsFilename);
|
|
if not FileExistsUTF8(AFilename) then exit;
|
|
if AProject.CompilerOptions.LoadFromFile(AFilename)<>mrOk then
|
|
DebugLn(['TMainIDE.DoLoadDefaultCompilerOptions failed']);
|
|
end;
|
|
|
|
function TMainIDE.DoNewProject(ProjectDesc: TProjectDescriptor):TModalResult;
|
|
var
|
|
i:integer;
|
|
HandlerResult: TModalResult;
|
|
begin
|
|
DebugLn('TMainIDE.DoNewProject A');
|
|
|
|
// init the descriptor (it can now ask the user for options)
|
|
Result:=ProjectDesc.InitDescriptor;
|
|
if Result<>mrOk then exit;
|
|
|
|
// close current project first
|
|
If Project1<>nil then begin
|
|
if SomethingOfProjectIsModified then begin
|
|
Result:=IDEQuestionDialog(lisProjectChanged, Format(lisSaveChangesToProject,
|
|
[Project1.GetTitleOrName]),
|
|
mtConfirmation, [mrYes, lisHintSave, mrNo, lisDiscardChanges, mrAbort,
|
|
dlgCancel]);
|
|
if Result=mrYes then begin
|
|
Result:=DoSaveProject([sfCanAbort]);
|
|
if Result=mrAbort then exit;
|
|
if Result<>mrOk then begin
|
|
Result:=IDEQuestionDialog(lisChangesWereNotSaved,
|
|
lisDoYouStillWantToCreateTheNewProject,
|
|
mtConfirmation, [mrYes, lisDiscardChangesCreateNewProject, mrAbort]);
|
|
if Result<>mrYes then exit;
|
|
end;
|
|
end else if Result<>mrNo then
|
|
exit;
|
|
end;
|
|
Result:=DoCloseProject;
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
|
|
// create a virtual project (i.e. unsaved and without real project directory)
|
|
|
|
// invalidate cached substituted macros
|
|
IncreaseCompilerParseStamp;
|
|
|
|
// switch codetools to virtual project directory
|
|
CodeToolBoss.GlobalValues.Variables[ExternalMacroStart+'ProjPath']:=
|
|
VirtualDirectory;
|
|
|
|
// create new project (TProject will automatically create the mainunit)
|
|
|
|
Project1:=CreateProjectObject(ProjectDesc,ProjectDescriptorProgram);
|
|
try
|
|
Project1.BeginUpdate(true);
|
|
try
|
|
Project1.CompilerOptions.CompilerPath:='$(CompPath)';
|
|
if pfUseDefaultCompilerOptions in Project1.Flags then begin
|
|
DoLoadDefaultCompilerOptions(Project1);
|
|
Project1.Flags:=Project1.Flags-[pfUseDefaultCompilerOptions];
|
|
end;
|
|
Project1.AutoAddOutputDirToIncPath;
|
|
UpdateCaption;
|
|
if ProjInspector<>nil then ProjInspector.LazProject:=Project1;
|
|
|
|
// add and load default required packages
|
|
PkgBoss.OpenProjectDependencies(Project1,true);
|
|
|
|
// rebuild codetools defines
|
|
MainBuildBoss.SetBuildTargetProject1(false);
|
|
|
|
// (i.e. remove old project specific things and create new)
|
|
IncreaseCompilerParseStamp;
|
|
Project1.DefineTemplates.AllChanged;
|
|
Project1.DefineTemplates.Active:=true;
|
|
DebugBoss.Reset;
|
|
|
|
finally
|
|
Project1.EndUpdate;
|
|
end;
|
|
|
|
Project1.BeginUpdate(true);
|
|
try
|
|
// create files
|
|
if ProjectDesc.CreateStartFiles(Project1)<>mrOk then begin
|
|
debugln('TMainIDE.DoNewProject ProjectDesc.CreateStartFiles failed');
|
|
end;
|
|
|
|
if (Project1.MainUnitInfo<>nil)
|
|
and ((Project1.FirstUnitWithEditorIndex=nil)
|
|
or ([pfMainUnitHasCreateFormStatements,pfMainUnitHasTitleStatement]*Project1.Flags=[]))
|
|
then begin
|
|
// the project has not created any secondary files
|
|
// or the project main source is not auto updated by the IDE
|
|
DoOpenMainUnit(-1,-1,[]);
|
|
end;
|
|
|
|
// init resource files
|
|
if not Project1.ProjResources.Regenerate(Project1.MainFilename, True, False,'') then
|
|
DebugLn('TMainIDE.DoNewProject Project1.Resources.Regenerate failed');
|
|
finally
|
|
Project1.EndUpdate;
|
|
end;
|
|
|
|
Result:=mrOk;
|
|
finally
|
|
// set all modified to false
|
|
Project1.UpdateAllVisibleUnits;
|
|
for i:=0 to Project1.UnitCount-1 do
|
|
Project1.Units[i].ClearModifieds;
|
|
Project1.Modified:=false;
|
|
// call handlers
|
|
HandlerResult:=DoCallProjectChangedHandler(lihtProjectOpened,Project1);
|
|
if not (HandlerResult in [mrOk,mrCancel,mrAbort]) then
|
|
HandlerResult:=mrCancel;
|
|
if (Result=mrOk) then
|
|
Result:=HandlerResult;
|
|
end;
|
|
|
|
//DebugLn('TMainIDE.DoNewProject end ');
|
|
end;
|
|
|
|
function TMainIDE.DoSaveProject(Flags: TSaveFlags):TModalResult;
|
|
var
|
|
i: integer;
|
|
AnUnitInfo: TUnitInfo;
|
|
SaveFileFlags: TSaveFlags;
|
|
begin
|
|
Result:=mrCancel;
|
|
if not (ToolStatus in [itNone,itDebugger]) then begin
|
|
Result:=mrAbort;
|
|
exit;
|
|
end;
|
|
|
|
SaveSourceEditorChangesToCodeCache(nil);
|
|
|
|
{$IFDEF IDE_DEBUG}
|
|
DebugLn('TMainIDE.DoSaveProject A SaveAs=',dbgs(sfSaveAs in Flags),' SaveToTestDir=',dbgs(sfSaveToTestDir in Flags),' ProjectInfoFile=',Project1.ProjectInfoFile);
|
|
{$ENDIF}
|
|
|
|
Result:=DoCheckFilesOnDisk(true);
|
|
if Result in [mrCancel,mrAbort] then exit;
|
|
|
|
if CheckMainSrcLCLInterfaces(sfQuietUnitCheck in Flags)<>mrOk then
|
|
exit(mrCancel);
|
|
|
|
// if this is a virtual project then save first the project info file
|
|
// to get a project directory
|
|
if Project1.IsVirtual
|
|
and ([sfSaveToTestDir,sfDoNotSaveVirtualFiles]*Flags=[])
|
|
then begin
|
|
Result:=SaveProjectInfo(Flags);
|
|
if Result in [mrCancel,mrAbort] then exit;
|
|
end;
|
|
|
|
if (not (sfDoNotSaveVirtualFiles in Flags)) then
|
|
begin
|
|
// check that all new units are saved first to get valid filenames
|
|
// (this can alter the mainunit: e.g. used unit names)
|
|
for i:=0 to Project1.UnitCount-1 do begin
|
|
AnUnitInfo:=Project1.Units[i];
|
|
if (AnUnitInfo.Loaded) and AnUnitInfo.IsVirtual
|
|
and AnUnitInfo.IsPartOfProject
|
|
and (Project1.MainUnitID<>i)
|
|
and (AnUnitInfo.OpenEditorInfoCount > 0) then begin
|
|
SaveFileFlags:=[sfSaveAs,sfProjectSaving]
|
|
+[sfCheckAmbiguousFiles]*Flags;
|
|
if sfSaveToTestDir in Flags then begin
|
|
if AnUnitInfo.IsPartOfProject or AnUnitInfo.IsVirtual then
|
|
Include(SaveFileFlags,sfSaveToTestDir);
|
|
end;
|
|
Result:=DoSaveEditorFile(AnUnitInfo.OpenEditorInfo[0].EditorComponent, SaveFileFlags);
|
|
if Result in [mrCancel,mrAbort] then exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Result:=SaveProjectInfo(Flags);
|
|
if Result in [mrCancel,mrAbort] then exit;
|
|
|
|
// save all editor files
|
|
for i:=0 to SourceEditorManager.SourceEditorCount-1 do begin
|
|
AnUnitInfo:=Project1.UnitWithEditorComponent(SourceEditorManager.SourceEditors[i]);
|
|
if (Project1.MainUnitID<0) or (Project1.MainUnitInfo <> AnUnitInfo) then begin
|
|
SaveFileFlags:=[sfProjectSaving]
|
|
+Flags*[sfCheckAmbiguousFiles];
|
|
if AnUnitInfo = nil
|
|
then begin
|
|
DebugLn('TMainIDE.DoSaveProject - unit not found for page %d', [i]);
|
|
DumpStack;
|
|
end else begin
|
|
if AnUnitInfo.IsVirtual
|
|
then begin
|
|
if (sfSaveToTestDir in Flags) then
|
|
Include(SaveFileFlags,sfSaveToTestDir)
|
|
else
|
|
continue;
|
|
end;
|
|
end;
|
|
Result:=DoSaveEditorFile(SourceEditorManager.SourceEditors[i], SaveFileFlags);
|
|
if Result=mrAbort then exit;
|
|
// mrCancel: continue saving other files
|
|
end;
|
|
end;
|
|
|
|
// update all lrs files
|
|
if sfSaveToTestDir in Flags then
|
|
MainBuildBoss.UpdateProjectAutomaticFiles(EnvironmentOptions.TestBuildDirectory)
|
|
else
|
|
MainBuildBoss.UpdateProjectAutomaticFiles('');
|
|
|
|
// everything went well => clear all modified flags
|
|
Project1.ClearModifieds(true);
|
|
|
|
// update menu and buttons state
|
|
UpdateSaveMenuItemsAndButtons(true);
|
|
|
|
{$IFDEF IDE_DEBUG}
|
|
DebugLn('TMainIDE.DoSaveProject End');
|
|
{$ENDIF}
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoCloseProject: TModalResult;
|
|
begin
|
|
{$IFDEF IDE_VERBOSE}
|
|
writeln('TMainIDE.DoCloseProject A');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoCloseProject A');{$ENDIF}
|
|
Result:=DebugBoss.DoStopProject;
|
|
if Result<>mrOk then begin
|
|
debugln('TMainIDE.DoCloseProject DebugBoss.DoStopProject failed');
|
|
exit;
|
|
end;
|
|
|
|
// call handlers
|
|
Result:=DoCallProjectChangedHandler(lihtProjectClose,Project1);
|
|
if Result=mrAbort then exit;
|
|
|
|
// close all loaded files
|
|
SourceEditorManager.IncUpdateLock;
|
|
try
|
|
while SourceEditorManager.SourceEditorCount > 0 do begin
|
|
Result:=DoCloseEditorFile(SourceEditorManager.SourceEditors[0],
|
|
[cfProjectClosing]);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
finally
|
|
SourceEditorManager.DecUpdateLock;
|
|
end;
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoCloseProject B');{$ENDIF}
|
|
IncreaseCompilerParseStamp;
|
|
// close Project
|
|
if ProjInspector<>nil then ProjInspector.LazProject:=nil;
|
|
FreeThenNil(Project1);
|
|
if IDEMessagesWindow<>nil then IDEMessagesWindow.Clear;
|
|
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoCloseProject C');{$ENDIF}
|
|
Result:=mrOk;
|
|
{$IFDEF IDE_VERBOSE}
|
|
writeln('TMainIDE.DoCloseProject end ',CodeToolBoss.ConsistencyCheck);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TMainIDE.DoOpenProjectFile(AFileName: string;
|
|
Flags: TOpenFlags): TModalResult;
|
|
var
|
|
Ext,AText,ACaption: string;
|
|
EditorInfoIndex, i: Integer;
|
|
NewBuf: TCodeBuffer;
|
|
LastDesigner: TDesigner;
|
|
AnUnitInfo: TUnitInfo;
|
|
FileReadable: Boolean;
|
|
HandlerResult: TModalResult;
|
|
AnEditorInfo: TUnitEditorInfo;
|
|
begin
|
|
// close the old project
|
|
if SomethingOfProjectIsModified then begin
|
|
Result:=IDEQuestionDialog(lisProjectChanged,
|
|
Format(lisSaveChangesToProject, [Project1.GetTitleOrName]),
|
|
mtconfirmation, [mrYes, mrNoToAll, lisNo, mbCancel], '');
|
|
if Result=mrNoToAll then
|
|
Result:=mrOk;
|
|
if Result=mrYes then begin
|
|
Result:=DoSaveProject([sfCanAbort]);
|
|
if Result=mrAbort then exit;
|
|
if Result<>mrOk then begin
|
|
Result:=IDEQuestionDialog(lisChangesWereNotSaved,
|
|
lisDoYouStillWantToOpenAnotherProject,
|
|
mtConfirmation, [mrOk, lisDiscardChangesAndOpenProject, mrAbort]);
|
|
end;
|
|
end;
|
|
if Result<>mrOk then exit(mrCancel);
|
|
end;
|
|
{$IFDEF IDE_VERBOSE}
|
|
writeln('TMainIDE.DoOpenProjectFile A "'+AFileName+'"');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoOpenProjectFile A');{$ENDIF}
|
|
Result:=mrCancel;
|
|
if ExtractFileNameOnly(AFileName)='' then exit;
|
|
//debugln('TMainIDE.DoOpenProjectFile A1 "'+AFileName+'"');
|
|
AFilename:=ExpandFileNameUTF8(TrimFilename(AFilename));
|
|
//debugln('TMainIDE.DoOpenProjectFile A2 "'+AFileName+'"');
|
|
if not FilenameIsAbsolute(AFilename) then
|
|
RaiseException('TMainIDE.DoOpenProjectFile: buggy ExpandFileNameUTF8');
|
|
|
|
// check if file exists
|
|
if not FileExistsUTF8(AFilename) then begin
|
|
ACaption:=lisFileNotFound;
|
|
AText:=Format(lisPkgMangFileNotFound, ['"', AFilename, '"']);
|
|
Result:=MessageDlg(ACaption, AText, mtError, [mbAbort], 0);
|
|
exit;
|
|
end;
|
|
|
|
// check symbolic link
|
|
Result:=ChooseSymlink(AFilename);
|
|
if Result<>mrOk then exit;
|
|
Ext:=lowercase(ExtractFileExt(AFilename));
|
|
|
|
// if there is a project info file, load that instead
|
|
if (Ext<>'.lpi') and (FileExistsUTF8(ChangeFileExt(AFileName,'.lpi'))) then
|
|
begin
|
|
// load instead of program file the project info file
|
|
AFileName:=ChangeFileExt(AFileName,'.lpi');
|
|
Ext:='.lpi';
|
|
end;
|
|
|
|
if (not FileUtil.FileIsText(AFilename,FileReadable)) and FileReadable then
|
|
begin
|
|
ACaption:=lisFileNotText;
|
|
AText:=Format(lisFileDoesNotLookLikeATextFileOpenItAnyway, ['"', AFilename,
|
|
'"', #13, #13]);
|
|
Result:=MessageDlg(ACaption, AText, mtConfirmation, [mbYes, mbAbort], 0);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
if not FileReadable then begin
|
|
Result:=QuestionDlg(lisUnableToReadFile,
|
|
Format(lisUnableToReadFilename, ['"', AFilename, '"']),
|
|
mtError, [mrCancel, lisSkipFile, mrAbort, lisAbortAllLoading], 0);
|
|
exit;
|
|
end;
|
|
|
|
if ofAddToRecent in Flags then
|
|
AddRecentProjectFileToEnvironment(AFileName);
|
|
|
|
Result:=DoCloseProject;
|
|
if Result=mrAbort then exit;
|
|
|
|
// create a new project
|
|
{$IFDEF IDE_VERBOSE}
|
|
writeln('TMainIDE.DoOpenProjectFile B');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoOpenProjectFile B');{$ENDIF}
|
|
Project1:=CreateProjectObject(ProjectDescriptorProgram,
|
|
ProjectDescriptorProgram);
|
|
|
|
EditorInfoIndex := 0;
|
|
SourceEditorManager.IncUpdateLock;
|
|
try
|
|
Project1.BeginUpdate(true);
|
|
try
|
|
if ProjInspector<>nil then ProjInspector.LazProject:=Project1;
|
|
|
|
// read project info file
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoOpenProjectFile B3');{$ENDIF}
|
|
Project1.ReadProject(AFilename);
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoOpenProjectFile B4');{$ENDIF}
|
|
Result:=DoCompleteLoadingProjectInfo;
|
|
finally
|
|
Project1.EndUpdate;
|
|
end;
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoOpenProjectFile B5');{$ENDIF}
|
|
if Result<>mrOk then exit;
|
|
|
|
if Project1.MainUnitID>=0 then begin
|
|
// read MainUnit Source
|
|
Result:=LoadCodeBuffer(NewBuf,Project1.MainFilename,
|
|
[lbfUpdateFromDisk,lbfRevert],false);// do not check if source is text
|
|
case Result of
|
|
mrOk: Project1.MainUnitInfo.Source:=NewBuf;
|
|
mrIgnore: Project1.MainUnitInfo.Source:=CodeToolBoss.CreateFile(Project1.MainFilename);
|
|
else exit(mrCancel);
|
|
end;
|
|
end;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TMainIDE.DoOpenProjectFile C');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoOpenProjectFile C');{$ENDIF}
|
|
IncreaseCompilerParseStamp;
|
|
|
|
// restore files
|
|
while EditorInfoIndex < Project1.AllEditorsInfoCount do begin
|
|
// TProject.ReadProject sorts alle UnitEditorInfos
|
|
AnEditorInfo := Project1.AllEditorsInfo[EditorInfoIndex];
|
|
AnUnitInfo := AnEditorInfo.UnitInfo;
|
|
if (not AnUnitInfo.Loaded) or (AnEditorInfo.PageIndex < 0) then begin
|
|
inc(EditorInfoIndex);
|
|
Continue;
|
|
end;
|
|
|
|
// reopen file
|
|
if (not AnUnitInfo.IsPartOfProject)
|
|
and (not FileExistsCached(AnUnitInfo.Filename)) then begin
|
|
// this file does not exist, but is not important => silently ignore
|
|
end
|
|
else begin
|
|
// reopen file
|
|
// This will adjust Page/WindowIndex if they are not continious
|
|
Result:=DoOpenEditorFile(AnUnitInfo.Filename, -1, AnEditorInfo.WindowIndex,
|
|
AnEditorInfo, [ofProjectLoading,ofMultiOpen,ofOnlyIfExists]);
|
|
if Result=mrAbort then
|
|
exit;
|
|
end;
|
|
if not ((AnUnitInfo.Filename<>'') and (AnEditorInfo.EditorComponent <> nil))
|
|
then begin
|
|
// failed to open
|
|
AnEditorInfo.PageIndex := -1;
|
|
// if failed entirely -> mark as unloaded, so that next time it will not be tried again
|
|
if AnUnitInfo.OpenEditorInfoCount = 0 then
|
|
AnUnitInfo.Loaded := False;
|
|
end;
|
|
inc(EditorInfoIndex);
|
|
end; // while EditorInfoIndex < Project1.AllEditorsInfoCount
|
|
Result:=mrCancel;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TMainIDE.DoOpenProjectFile D');
|
|
{$ENDIF}
|
|
|
|
// set active editor source editor
|
|
for i := 0 to Project1.AllEditorsInfoCount - 1 do begin
|
|
AnEditorInfo := Project1.AllEditorsInfo[i];
|
|
if AnEditorInfo.IsVisibleTab then
|
|
begin
|
|
if AnEditorInfo.WindowIndex >= SourceEditorManager.SourceWindowCount
|
|
then begin
|
|
// session info is invalid (buggy lps file?) => auto fix
|
|
AnEditorInfo.IsVisibleTab:=false;
|
|
AnEditorInfo.WindowIndex:=-1;
|
|
end;
|
|
if (AnEditorInfo.WindowIndex < 0) then continue;
|
|
if (SourceEditorManager.SourceWindows[AnEditorInfo.WindowIndex] <> nil)
|
|
then begin
|
|
SourceEditorManager.SourceWindows
|
|
[AnEditorInfo.WindowIndex].PageIndex := AnEditorInfo.PageIndex;
|
|
end;
|
|
end;
|
|
end;
|
|
if (Project1.ActiveWindowIndexAtStart<0)
|
|
or (Project1.ActiveWindowIndexAtStart >= SourceEditorManager.SourceWindowCount)
|
|
then begin
|
|
// session info is invalid (buggy lps file?) => auto fix
|
|
Project1.ActiveWindowIndexAtStart := 0;
|
|
end;
|
|
if (Project1.ActiveWindowIndexAtStart >= 0) and
|
|
(Project1.ActiveWindowIndexAtStart < SourceEditorManager.SourceWindowCount)
|
|
then begin
|
|
SourceEditorManager.ActiveSourceWindow :=
|
|
SourceEditorManager.SourceWindows[Project1.ActiveWindowIndexAtStart];
|
|
SourceEditorManager.ShowActiveWindowOnTop(True);
|
|
end;
|
|
|
|
if ([ofDoNotLoadResource]*Flags=[])
|
|
and ( (not Project1.AutoOpenDesignerFormsDisabled)
|
|
and EnvironmentOptions.AutoCreateFormsOnOpen
|
|
and (SourceEditorManager.ActiveEditor<>nil) )
|
|
then begin
|
|
// auto open form of active unit
|
|
AnUnitInfo:=Project1.UnitWithEditorComponent(SourceEditorManager.ActiveEditor);
|
|
if AnUnitInfo<>nil then
|
|
Result:=DoLoadLFM(AnUnitInfo,[ofProjectLoading,ofMultiOpen,ofOnlyIfExists],
|
|
[cfSaveDependencies]);
|
|
end;
|
|
|
|
// select a form (object inspector, formeditor, control selection)
|
|
if FLastFormActivated<>nil then begin
|
|
LastDesigner:=TDesigner(FLastFormActivated.Designer);
|
|
debugln(['TMainIDE.DoOpenProjectFile ',DbgSName(FLastFormActivated),' ',DbgSName(FLastFormActivated.Designer)]);
|
|
LastDesigner.SelectOnlyThisComponent(LastDesigner.LookupRoot);
|
|
end;
|
|
|
|
// set all modified to false
|
|
Project1.UpdateAllVisibleUnits;
|
|
Project1.ClearModifieds(true);
|
|
|
|
IncreaseCompilerParseStamp;
|
|
IDEProtocolOpts.LastProjectLoadingCrashed := False;
|
|
Result:=mrOk;
|
|
finally
|
|
SourceEditorManager.DecUpdateLock;
|
|
if (Result<>mrOk) and (Project1<>nil) then begin
|
|
// mark all files, that are left to open as unloaded:
|
|
for i := EditorInfoIndex to Project1.AllEditorsInfoCount - 1 do begin
|
|
AnEditorInfo := Project1.AllEditorsInfo[i];
|
|
AnEditorInfo.PageIndex := -1;
|
|
AnUnitInfo := AnEditorInfo.UnitInfo;
|
|
if AnUnitInfo.Loaded and (AnUnitInfo.OpenEditorInfoCount = 0) then
|
|
AnUnitInfo.Loaded := false;
|
|
end;
|
|
end;
|
|
// call handlers
|
|
HandlerResult:=DoCallProjectChangedHandler(lihtProjectOpened,Project1);
|
|
if not (HandlerResult in [mrOk,mrCancel,mrAbort]) then
|
|
HandlerResult:=mrCancel;
|
|
if (Result=mrOk) then
|
|
Result:=HandlerResult;
|
|
end;
|
|
if Result=mrAbort then exit;
|
|
{$IFDEF IDE_VERBOSE}
|
|
debugln('TMainIDE.DoOpenProjectFile end CodeToolBoss.ConsistencyCheck=',IntToStr(CodeToolBoss.ConsistencyCheck));
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoOpenProjectFile end');{$ENDIF}
|
|
end;
|
|
|
|
function TMainIDE.DoPublishProject(Flags: TSaveFlags;
|
|
ShowDialog: boolean): TModalResult;
|
|
begin
|
|
// show the publish project dialog
|
|
if ShowDialog then begin
|
|
Result:=ShowPublishProjectDialog(Project1.PublishOptions);
|
|
Project1.Modified:=Project1.PublishOptions.Modified;
|
|
if Result<>mrOk then exit;
|
|
IncreaseCompilerParseStamp;
|
|
end;
|
|
|
|
//debugln('TMainIDE.DoPublishProject A');
|
|
// save project
|
|
Result:=DoSaveProject(Flags);
|
|
if Result<>mrOk then exit;
|
|
|
|
// publish project
|
|
//debugln('TMainIDE.DoPublishProject B');
|
|
Result:=DoPublishModule(Project1.PublishOptions,Project1.ProjectDirectory,
|
|
MainBuildBoss.GetProjectPublishDir);
|
|
end;
|
|
|
|
function TMainIDE.DoImExportCompilerOptions(Sender: TObject; out ImportExportResult: TImportExportOptionsResult): TModalResult;
|
|
var
|
|
Options: TCompilerOptions;
|
|
Filename: string;
|
|
begin
|
|
Result := mrOk;
|
|
if Sender is TCompilerOptions then
|
|
Options := TCompilerOptions(Sender)
|
|
else
|
|
RaiseException('TMainIDE.OnCompilerOptionsImExport');
|
|
ImportExportResult := ShowImExportCompilerOptionsDialog(Options, Filename);
|
|
if Filename='' then Exit(mrCancel);
|
|
case ImportExportResult of
|
|
ieorImport: Result := DoImportCompilerOptions(Options, Filename);
|
|
ieorExport: Result := DoExportCompilerOptions(Options, Filename);
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.DoShowProjectInspector(Show: boolean);
|
|
begin
|
|
if ProjInspector=nil then begin
|
|
ProjInspector:=TProjectInspectorForm.Create(OwningComponent);
|
|
ProjInspector.OnOpen:=@ProjInspectorOpen;
|
|
ProjInspector.OnShowOptions:=@mnuProjectOptionsClicked;
|
|
ProjInspector.OnAddUnitToProject:=@ProjInspectorAddUnitToProject;
|
|
ProjInspector.OnAddDependency:=@PkgBoss.OnProjectInspectorAddDependency;
|
|
ProjInspector.OnRemoveFile:=@ProjInspectorRemoveFile;
|
|
ProjInspector.OnRemoveDependency:=
|
|
@PkgBoss.OnProjectInspectorRemoveDependency;
|
|
ProjInspector.OnReAddDependency:=
|
|
@PkgBoss.OnProjectInspectorReAddDependency;
|
|
|
|
ProjInspector.LazProject:=Project1;
|
|
end;
|
|
if Show then
|
|
IDEWindowCreators.ShowForm(ProjInspector,true);
|
|
end;
|
|
|
|
function TMainIDE.DoCreateProjectForProgram(
|
|
ProgramBuf: TCodeBuffer): TModalResult;
|
|
var
|
|
NewProjectDesc: TProjectDescriptor;
|
|
MainUnitInfo: TUnitInfo;
|
|
begin
|
|
{$IFDEF IDE_VERBOSE}
|
|
writeln('[TMainIDE.DoCreateProjectForProgram] A ',ProgramBuf.Filename);
|
|
{$ENDIF}
|
|
Result:=DoSaveProjectIfChanged;
|
|
if Result=mrAbort then exit;
|
|
|
|
// let user choose the program type
|
|
NewProjectDesc:=nil;
|
|
if ChooseNewProject(NewProjectDesc)<>mrOk then exit;
|
|
|
|
// close old project
|
|
If Project1<>nil then begin
|
|
if DoCloseProject=mrAbort then begin
|
|
Result:=mrAbort;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
// reload file (if the file was open in the IDE, closeproject unloaded it)
|
|
ProgramBuf.Reload;
|
|
|
|
// switch codetools to new project directory
|
|
CodeToolBoss.GlobalValues.Variables[ExternalMacroStart+'ProjPath']:=
|
|
ExpandFileNameUTF8(ExtractFilePath(ProgramBuf.Filename));
|
|
|
|
// create a new project
|
|
Project1:=CreateProjectObject(NewProjectDesc,ProjectDescriptorProgram);
|
|
Project1.BeginUpdate(true);
|
|
try
|
|
if ProjInspector<>nil then ProjInspector.LazProject:=Project1;
|
|
MainUnitInfo:=Project1.MainUnitInfo;
|
|
MainUnitInfo.Source:=ProgramBuf;
|
|
Project1.ProjectInfoFile:=ChangeFileExt(ProgramBuf.Filename,'.lpi');
|
|
DoLoadDefaultCompilerOptions(Project1);
|
|
UpdateCaption;
|
|
IncreaseCompilerParseStamp;
|
|
|
|
// add and load default required packages
|
|
PkgBoss.OpenProjectDependencies(Project1,true);
|
|
|
|
Result:=DoCompleteLoadingProjectInfo;
|
|
if Result<>mrOk then exit;
|
|
finally
|
|
Project1.EndUpdate;
|
|
end;
|
|
|
|
// show program unit
|
|
Result:=DoOpenEditorFile(ProgramBuf.Filename,-1,-1,
|
|
[ofAddToRecent,ofRegularFile]);
|
|
if Result=mrAbort then exit;
|
|
|
|
{$IFDEF IDE_VERBOSE}
|
|
writeln('[TMainIDE.DoCreateProjectForProgram] END');
|
|
{$ENDIF}
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoSaveProjectIfChanged: TModalResult;
|
|
begin
|
|
if SomethingOfProjectIsModified then begin
|
|
if MessageDlg(lisProjectChanged, Format(lisSaveChangesToProject,
|
|
[Project1.GetTitleOrName]),
|
|
mtconfirmation, [mbYes, mbNo, mbCancel], 0)=mrYes then
|
|
begin
|
|
if DoSaveProject([])=mrAbort then begin
|
|
Result:=mrAbort;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoAddActiveUnitToProject: TModalResult;
|
|
var
|
|
ActiveSourceEditor: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
s, ShortUnitName: string;
|
|
DependencyAdded: boolean;
|
|
Owners: TFPList;
|
|
i: Integer;
|
|
APackage: TLazPackage;
|
|
MsgResult: TModalResult;
|
|
begin
|
|
Result:=mrCancel;
|
|
if not BeginCodeTool(ActiveSourceEditor,ActiveUnitInfo,[]) then exit;
|
|
if (ActiveUnitInfo=nil) then exit;
|
|
if ActiveUnitInfo.IsPartOfProject then begin
|
|
if not ActiveUnitInfo.IsVirtual then
|
|
s:=Format(lisTheFile, ['"', ActiveUnitInfo.Filename, '"'])
|
|
else
|
|
s:=Format(lisTheFile, ['"', ActiveSourceEditor.PageName, '"']);
|
|
s:=Format(lisisAlreadyPartOfTheProject, [s]);
|
|
MessageDlg(s,mtInformation,[mbOk],0);
|
|
exit;
|
|
end;
|
|
if not ActiveUnitInfo.IsVirtual then
|
|
s:='"'+ActiveUnitInfo.Filename+'"'
|
|
else
|
|
s:='"'+ActiveSourceEditor.PageName+'"';
|
|
if (ActiveUnitInfo.Unit_Name<>'')
|
|
and (Project1.IndexOfUnitWithName(ActiveUnitInfo.Unit_Name,
|
|
true,ActiveUnitInfo)>=0) then
|
|
begin
|
|
MessageDlg(Format(
|
|
lisUnableToAddToProjectBecauseThereIsAlreadyAUnitWith, [s]),
|
|
mtInformation, [mbOk], 0);
|
|
exit;
|
|
end;
|
|
|
|
Owners:=PkgBoss.GetPossibleOwnersOfUnit(ActiveUnitInfo.Filename,[]);
|
|
try
|
|
if (Owners<>nil) then begin
|
|
for i:=0 to Owners.Count-1 do begin
|
|
if TObject(Owners[i]) is TLazPackage then begin
|
|
APackage:=TLazPackage(Owners[i]);
|
|
MsgResult:=IDEQuestionDialog(lisAddPackageRequirement,
|
|
Format(lisTheUnitBelongsToPackage, [APackage.IDAsString]),
|
|
mtConfirmation, [mrYes, lisAddPackageToProject2,
|
|
mrIgnore, lisAddUnitNotRecommended,
|
|
mrCancel],'');
|
|
case MsgResult of
|
|
mrYes:
|
|
begin
|
|
PkgBoss.AddProjectDependency(Project1,APackage);
|
|
exit;
|
|
end;
|
|
mrIgnore: ;
|
|
else
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
Owners.Free;
|
|
end;
|
|
|
|
if FilenameIsPascalUnit(ActiveUnitInfo.Filename)
|
|
and (EnvironmentOptions.CharcaseFileAction<>ccfaIgnore) then
|
|
begin
|
|
// ask user to apply naming conventions
|
|
Result:=DoRenameUnitLowerCase(ActiveUnitInfo,true);
|
|
if Result=mrIgnore then Result:=mrOk;
|
|
if Result<>mrOk then begin
|
|
debugln('TMainIDE.DoAddActiveUnitToProject A DoRenameUnitLowerCase failed ',ActiveUnitInfo.Filename);
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
if MessageDlg(Format(lisAddToProject, [s]), mtConfirmation, [mbYes,
|
|
mbCancel], 0) in [mrOk,mrYes]
|
|
then begin
|
|
DependencyAdded:=false;
|
|
if FilenameIsPascalUnit(ActiveUnitInfo.Filename) then
|
|
CheckDirIsInUnitSearchPath(ActiveUnitInfo,false,DependencyAdded)
|
|
else if CompareFileExt(ActiveUnitInfo.Filename,'inc',false)=0 then
|
|
CheckDirIsInIncludeSearchPath(ActiveUnitInfo,false,DependencyAdded);
|
|
if not DependencyAdded then begin
|
|
ActiveUnitInfo.IsPartOfProject:=true;
|
|
Project1.Modified:=true;
|
|
if (FilenameIsPascalUnit(ActiveUnitInfo.Filename))
|
|
and (pfMainUnitHasUsesSectionForAllUnits in Project1.Flags)
|
|
then begin
|
|
ActiveUnitInfo.ReadUnitNameFromSource(false);
|
|
ShortUnitName:=ActiveUnitInfo.CreateUnitName;
|
|
if (ShortUnitName<>'') then begin
|
|
if CodeToolBoss.AddUnitToMainUsesSection(
|
|
Project1.MainUnitInfo.Source,ShortUnitName,'')
|
|
then
|
|
Project1.MainUnitInfo.Modified:=true;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoRemoveFromProjectDialog: TModalResult;
|
|
var
|
|
ViewUnitEntries: TStringList;
|
|
i:integer;
|
|
AName: string;
|
|
AnUnitInfo: TUnitInfo;
|
|
UnitInfos: TFPList;
|
|
const
|
|
MultiSelectCheckedState: Boolean = true;
|
|
Begin
|
|
ViewUnitEntries := TStringList.Create;
|
|
ViewUnitEntries.Sorted := True;
|
|
UnitInfos:=nil;
|
|
try
|
|
for i := 0 to Project1.UnitCount-1 do
|
|
begin
|
|
AnUnitInfo:=Project1.Units[i];
|
|
if (AnUnitInfo.IsPartOfProject) and (i<>Project1.MainUnitID) then
|
|
begin
|
|
AName := Project1.RemoveProjectPathFromFilename(AnUnitInfo.FileName);
|
|
ViewUnitEntries.AddObject(AName, TViewUnitsEntry.Create(AName,i,false));
|
|
end;
|
|
end;
|
|
if ShowViewUnitsDlg(ViewUnitEntries, true, MultiSelectCheckedState,
|
|
lisRemoveFromProject, IDEImages.LoadImage(16, 'item_unit')) <> mrOk then
|
|
exit(mrOk);
|
|
{ This is where we check what the user selected. }
|
|
UnitInfos:=TFPList.Create;
|
|
for i:=0 to ViewUnitEntries.Count-1 do
|
|
begin
|
|
if TViewUnitsEntry(ViewUnitEntries.Objects[i]).Selected then
|
|
begin
|
|
AnUnitInfo:=Project1.Units[TViewUnitsEntry(ViewUnitEntries.Objects[i]).ID];
|
|
if AnUnitInfo.IsPartOfProject then
|
|
UnitInfos.Add(AnUnitInfo);
|
|
end;
|
|
end;
|
|
if UnitInfos.Count>0 then
|
|
Result:=RemoveFilesFromProject(Project1,UnitInfos)
|
|
else
|
|
Result:=mrOk;
|
|
finally
|
|
UnitInfos.Free;
|
|
for i := 0 to ViewUnitEntries.Count-1 do
|
|
TViewUnitsEntry(ViewUnitEntries.Objects[i]).Free;
|
|
ViewUnitEntries.Free;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoWarnAmbiguousFiles: TModalResult;
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
i: integer;
|
|
DestFilename: string;
|
|
begin
|
|
for i:=0 to Project1.UnitCount-1 do begin
|
|
AnUnitInfo:=Project1.Units[i];
|
|
if (AnUnitInfo.IsPartOfProject) and (not AnUnitInfo.IsVirtual) then begin
|
|
DestFilename:=MainBuildBoss.GetTargetUnitFilename(AnUnitInfo);
|
|
Result:=MainBuildBoss.CheckAmbiguousSources(DestFilename,true);
|
|
if Result<>mrOk then exit;
|
|
end;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
procedure TMainIDE.DoUpdateProjectResourceInfo;
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
LFMFilename: String;
|
|
begin
|
|
AnUnitInfo:=Project1.FirstPartOfProject;
|
|
while AnUnitInfo<>nil do begin
|
|
if (not AnUnitInfo.HasResources)
|
|
and (not AnUnitInfo.IsVirtual) and FilenameIsPascalUnit(AnUnitInfo.Filename)
|
|
then begin
|
|
LFMFilename:=ChangeFileExt(AnUnitInfo.Filename,'.lfm');
|
|
if not FileExistsUTF8(LFMFilename) then
|
|
LFMFilename:=ChangeFileExt(AnUnitInfo.Filename,'.dfm');
|
|
AnUnitInfo.HasResources:=FileExistsUTF8(LFMFilename);
|
|
end;
|
|
AnUnitInfo:=AnUnitInfo.NextPartOfProject;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoSaveForBuild(AReason: TCompileReason): TModalResult;
|
|
begin
|
|
Result:=mrCancel;
|
|
if not (ToolStatus in [itNone,itDebugger]) then begin
|
|
{$IFDEF VerboseSaveForBuild}
|
|
DebugLn('TMainIDE.DoSaveForBuild ToolStatus disallows it');
|
|
{$ENDIF}
|
|
Result:=mrAbort;
|
|
exit;
|
|
end;
|
|
if Project1=nil then Begin
|
|
MessageDlg(lisCreateAProjectFirst, mterror, [mbok], 0);
|
|
Exit;
|
|
end;
|
|
|
|
// save all files
|
|
{$IFDEF VerboseSaveForBuild}
|
|
DebugLn('TMainIDE.DoSaveForBuild Project1.IsVirtual=',dbgs(Project1.IsVirtual));
|
|
{$ENDIF}
|
|
|
|
if not Project1.IsVirtual then
|
|
Result:=DoSaveAll([sfCheckAmbiguousFiles])
|
|
else
|
|
Result:=DoSaveProjectToTestDirectory([sfSaveNonProjectFiles]);
|
|
Project1.ProjResources.DoBeforeBuild(AReason, Project1.IsVirtual);
|
|
Project1.UpdateExecutableType;
|
|
if Result<>mrOk then begin
|
|
{$IFDEF VerboseSaveForBuild}
|
|
DebugLn('TMainIDE.DoSaveForBuild project saving failed');
|
|
{$ENDIF}
|
|
exit;
|
|
end;
|
|
|
|
Result:=PkgBoss.DoSaveAllPackages([]);
|
|
end;
|
|
|
|
function TMainIDE.DoCheckIfProjectNeedsCompilation(AProject: TProject;
|
|
const CompilerFilename, CompilerParams, SrcFilename: string;
|
|
out NeedBuildAllFlag: boolean): TModalResult;
|
|
var
|
|
StateFilename: String;
|
|
StateFileAge: LongInt;
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
NeedBuildAllFlag:=false;
|
|
if (AProject.LastCompilerFilename<>CompilerFilename)
|
|
or (AProject.LastCompilerParams<>CompilerParams)
|
|
or ((AProject.LastCompilerFileDate>0)
|
|
and FileExistsCached(CompilerFilename)
|
|
and (FileAgeCached(CompilerFilename)<>AProject.LastCompilerFileDate))
|
|
then
|
|
NeedBuildAllFlag:=true;
|
|
|
|
// check state file
|
|
StateFilename:=AProject.GetStateFilename;
|
|
Result:=AProject.LoadStateFile(false);
|
|
if Result<>mrOk then exit;
|
|
if not (lpsfStateFileLoaded in AProject.StateFlags) then begin
|
|
DebugLn('TMainIDE.CheckIfPackageNeedsCompilation No state file for ',AProject.IDAsString);
|
|
exit(mrYes);
|
|
end;
|
|
|
|
StateFileAge:=FileAgeCached(StateFilename);
|
|
|
|
// check main source file
|
|
if FileExistsCached(SrcFilename) and (StateFileAge<FileAgeCached(SrcFilename)) then
|
|
begin
|
|
DebugLn('TMainIDE.CheckIfProjectNeedsCompilation SrcFile outdated ',AProject.IDAsString);
|
|
exit(mrYes);
|
|
end;
|
|
|
|
// check compiler and params
|
|
if CompilerFilename<>AProject.LastCompilerFilename then begin
|
|
DebugLn('TMainIDE.CheckIfProjectNeedsCompilation Compiler filename changed for ',AProject.IDAsString);
|
|
DebugLn(' Old="',AProject.LastCompilerFilename,'"');
|
|
DebugLn(' Now="',CompilerFilename,'"');
|
|
exit(mrYes);
|
|
end;
|
|
if not FileExistsUTF8(CompilerFilename) then begin
|
|
DebugLn('TMainIDE.CheckIfProjectNeedsCompilation Compiler filename not found for ',AProject.IDAsString);
|
|
DebugLn(' File="',CompilerFilename,'"');
|
|
exit(mrYes);
|
|
end;
|
|
if FileAgeCached(CompilerFilename)<>AProject.LastCompilerFileDate then begin
|
|
DebugLn('TMainIDE.CheckIfProjectNeedsCompilation Compiler file changed for ',AProject.IDAsString);
|
|
DebugLn(' File="',CompilerFilename,'"');
|
|
exit(mrYes);
|
|
end;
|
|
if CompilerParams<>AProject.LastCompilerParams then begin
|
|
DebugLn('TMainIDE.CheckIfProjectNeedsCompilation Compiler params changed for ',AProject.IDAsString);
|
|
DebugLn(' Old="',AProject.LastCompilerParams,'"');
|
|
DebugLn(' Now="',CompilerParams,'"');
|
|
exit(mrYes);
|
|
end;
|
|
|
|
// compiler and parameters are the same
|
|
// quick compile is possible
|
|
NeedBuildAllFlag:=false;
|
|
|
|
// check all required packages
|
|
Result:=PackageGraph.CheckCompileNeedDueToDependencies(AProject,
|
|
AProject.FirstRequiredDependency,
|
|
not (pfUseDesignTimePackages in AProject.Flags),
|
|
StateFileAge);
|
|
if Result<>mrNo then exit;
|
|
|
|
// check project files
|
|
AnUnitInfo:=AProject.FirstPartOfProject;
|
|
while AnUnitInfo<>nil do begin
|
|
if FileExistsCached(AnUnitInfo.Filename)
|
|
and (StateFileAge<FileAgeCached(AnUnitInfo.Filename)) then begin
|
|
DebugLn('TMainIDE.CheckIfProjectNeedsCompilation Src has changed ',AProject.IDAsString,' ',AnUnitInfo.Filename);
|
|
exit(mrYes);
|
|
end;
|
|
AnUnitInfo:=AnUnitInfo.NextPartOfProject;
|
|
end;
|
|
|
|
// check all open editor files (maybe the user forgot to add them to the project)
|
|
AnUnitInfo:=AProject.FirstUnitWithEditorIndex;
|
|
while AnUnitInfo<>nil do begin
|
|
if (not AnUnitInfo.IsPartOfProject)
|
|
and FileExistsCached(AnUnitInfo.Filename)
|
|
and (StateFileAge<FileAgeCached(AnUnitInfo.Filename)) then begin
|
|
DebugLn('TMainIDE.CheckIfProjectNeedsCompilation Editor Src has changed ',AProject.IDAsString,' ',AnUnitInfo.Filename);
|
|
exit(mrYes);
|
|
end;
|
|
AnUnitInfo:=AnUnitInfo.NextUnitWithEditorIndex;
|
|
end;
|
|
|
|
Result:=mrNo;
|
|
end;
|
|
|
|
function TMainIDE.DoSaveProjectToTestDirectory(Flags: TSaveFlags): TModalResult;
|
|
begin
|
|
Result:=mrCancel;
|
|
if (EnvironmentOptions.TestBuildDirectory='')
|
|
or (not DirPathExists(EnvironmentOptions.TestBuildDirectory)) then begin
|
|
if (EnvironmentOptions.TestBuildDirectory<>'') then begin
|
|
MessageDlg(Format(lisTheTestDirectoryCouldNotBeFoundSeeIDEOpt, [
|
|
#13, '"', EnvironmentOptions.TestBuildDirectory, '"', #13]), mtError, [
|
|
mbCancel], 0);
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
Result:=MessageDlg(lisBuildNewProject,
|
|
Format(lisTheProjectMustBeSavedBeforeBuildingIfYouSetTheTest, [#13, #13,
|
|
#13]), mtInformation, [mbYes, mbNo], 0);
|
|
if Result<>mrYes then exit;
|
|
Result:=DoSaveAll([sfCheckAmbiguousFiles]);
|
|
exit;
|
|
end;
|
|
Result:=DoSaveProject([sfSaveToTestDir,sfCheckAmbiguousFiles]+Flags);
|
|
end;
|
|
|
|
function TMainIDE.DoTestCompilerSettings(
|
|
TheCompilerOptions: TCompilerOptions): TModalResult;
|
|
begin
|
|
Result:=mrCancel;
|
|
if (Project1=nil) or (ToolStatus<>itNone) then exit;
|
|
|
|
// change tool status
|
|
CheckCompilerOptsDlg:=TCheckCompilerOptsDlg.Create(nil);
|
|
try
|
|
CheckCompilerOptsDlg.Options:=TheCompilerOptions;
|
|
CheckCompilerOptsDlg.MacroList:=GlobalMacroList;
|
|
Result:=CheckCompilerOptsDlg.ShowModal;
|
|
finally
|
|
FreeThenNil(CheckCompilerOptsDlg);
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.CheckMainSrcLCLInterfaces(Silent: boolean): TModalResult;
|
|
var
|
|
MainUnitInfo: TUnitInfo;
|
|
MainUsesSection,ImplementationUsesSection: TStrings;
|
|
MsgResult: TModalResult;
|
|
begin
|
|
Result:=mrOk;
|
|
if (Project1=nil) then exit;
|
|
if Project1.SkipCheckLCLInterfaces then exit;
|
|
MainUnitInfo:=Project1.MainUnitInfo;
|
|
if (MainUnitInfo=nil) or (MainUnitInfo.Source=nil) then exit;
|
|
if PackageGraph.FindDependencyRecursively(Project1.FirstRequiredDependency,
|
|
PackageGraph.LCLPackage)=nil
|
|
then
|
|
exit; // project does not use LCL
|
|
// project uses LCL
|
|
MainUsesSection:=nil;
|
|
ImplementationUsesSection:=nil;
|
|
try
|
|
if not CodeToolBoss.FindUsedUnitNames(MainUnitInfo.Source,
|
|
MainUsesSection,ImplementationUsesSection) then exit;
|
|
if (AnsiSearchInStringList(MainUsesSection,'forms')<0)
|
|
and (AnsiSearchInStringList(ImplementationUsesSection,'forms')<0) then
|
|
exit;
|
|
// project uses lcl unit Forms
|
|
if (AnsiSearchInStringList(MainUsesSection,'interfaces')>=0)
|
|
or (AnsiSearchInStringList(ImplementationUsesSection,'interfaces')>=0) then
|
|
exit;
|
|
// project uses lcl unit Forms, but not unit interfaces
|
|
// this will result in strange linker error
|
|
if not Silent then
|
|
begin
|
|
MsgResult:=IDEQuestionDialog(lisCCOWarningCaption,
|
|
Format(lisTheProjectDoesNotUseTheLCLUnitInterfacesButItSeems, [#13])
|
|
, mtWarning, [mrYes, lisAddUnitInterfaces, mrNo, dlgIgnoreVerb,
|
|
mrNoToAll, lisAlwaysIgnore, mrCancel]);
|
|
case MsgResult of
|
|
mrNo: exit;
|
|
mrNoToAll: begin Project1.SkipCheckLCLInterfaces:=true; exit; end;
|
|
mrCancel: exit(mrCancel);
|
|
end;
|
|
end;
|
|
CodeToolBoss.AddUnitToMainUsesSection(MainUnitInfo.Source,'Interfaces','');
|
|
finally
|
|
MainUsesSection.Free;
|
|
ImplementationUsesSection.Free;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.QuitIDE: boolean;
|
|
begin
|
|
Result:=true;
|
|
MainIDEBar.OnCloseQuery(Self, Result);
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TMainIDE.QuitIDE 1');
|
|
{$ENDIF}
|
|
if Result then MainIDEBar.Close;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TMainIDE.QuitIDE 2');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function CheckCompileReasons(Reason: TCompileReason;
|
|
Options: TProjectCompilerOptions; Quiet: boolean): TModalResult;
|
|
var
|
|
ProjToolOpts: TProjectCompilationToolOptions;
|
|
begin
|
|
if (Reason in Options.CompileReasons)
|
|
and (Options.CompilerPath<>'') then
|
|
exit(mrOk);
|
|
if Options.ExecuteBefore is TProjectCompilationToolOptions then begin
|
|
ProjToolOpts:=TProjectCompilationToolOptions(Options.ExecuteBefore);
|
|
if (Reason in ProjToolOpts.CompileReasons) and (ProjToolOpts.Command<>'') then
|
|
exit(mrOk);
|
|
end;
|
|
if Options.ExecuteAfter is TProjectCompilationToolOptions then begin
|
|
ProjToolOpts:=TProjectCompilationToolOptions(Options.ExecuteAfter);
|
|
if (Reason in ProjToolOpts.CompileReasons) and (ProjToolOpts.Command<>'') then
|
|
exit(mrOk);
|
|
end;
|
|
// reason is not handled
|
|
if Quiet then exit(mrCancel);
|
|
Result:=MessageDlg('Nothing to do',
|
|
'The project''s compiler options has no compile command.'#13
|
|
+'See Project / Compiler Options ... / Compilation',mtInformation,
|
|
[mbCancel,mbIgnore],0);
|
|
if Result=mrIgnore then
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoBuildProject(const AReason: TCompileReason;
|
|
Flags: TProjectBuildFlags): TModalResult;
|
|
var
|
|
SrcFilename: string;
|
|
ToolBefore: TProjectCompilationToolOptions;
|
|
ToolAfter: TProjectCompilationToolOptions;
|
|
PkgFlags: TPkgCompileFlags;
|
|
CompilerFilename: String;
|
|
WorkingDir: String;
|
|
CompilerParams: String;
|
|
NeedBuildAllFlag: Boolean;
|
|
UnitOutputDirectory: String;
|
|
TargetExeName: String;
|
|
err : TFPCErrorType;
|
|
TargetExeDirectory: String;
|
|
FPCVersion, FPCRelease, FPCPatch: integer;
|
|
begin
|
|
if Project1.MainUnitInfo=nil then begin
|
|
// this project has no source to compile
|
|
IDEMessageDialog(lisCanNotCompileProject,
|
|
lisTheProjectHasNoMainSourceFile, mtError, [mbCancel], '');
|
|
exit(mrCancel);
|
|
end;
|
|
|
|
Result:=PrepareForCompile;
|
|
if Result<>mrOk then exit;
|
|
|
|
if (AReason in [crCompile,crBuild])
|
|
and ([pbfDoNotCompileProject,pbfSkipTools]*Flags=[]) then
|
|
begin
|
|
// warn if nothing to do
|
|
Result:=CheckCompileReasons(AReason,Project1.CompilerOptions,false);
|
|
if Result<>mrOk then exit;
|
|
end;
|
|
|
|
// show messages
|
|
IDEWindowCreators.ShowForm(MessagesView,EnvironmentOptions.MsgViewFocus);
|
|
MessagesView.BeginBlock;
|
|
|
|
try
|
|
Result:=DoSaveForBuild(AReason);
|
|
if Result<>mrOk then exit;
|
|
|
|
if (Project1.ProjResources.ResourceType=rtRes) then begin
|
|
// FPC resources are only supported with FPC 2.4+
|
|
CodeToolBoss.GetFPCVersionForDirectory(
|
|
ExtractFilePath(Project1.MainFilename),FPCVersion,FPCRelease,FPCPatch);
|
|
if (FPCVersion=2) and (FPCRelease<4) then begin
|
|
MessageDlg(lisFPCTooOld,
|
|
lisTheProjectUsesTheNewFPCResourcesWhichRequiresAtLea,
|
|
mtError,[mbCancel],0);
|
|
exit(mrCancel);
|
|
end;
|
|
end;
|
|
|
|
CompileProgress.CreateDialog(OwningComponent, Project1.MainFilename, lisInfoBuildComplile);
|
|
|
|
// clear old error lines
|
|
SourceEditorManager.ClearErrorLines;
|
|
DoArrangeSourceEditorAndMessageView(false);
|
|
|
|
// now building can start: call handler
|
|
Result:=DoCallModalFunctionHandler(lihtProjectBuilding);
|
|
if Result<>mrOk then exit;
|
|
|
|
// get main source filename
|
|
if not Project1.IsVirtual then begin
|
|
WorkingDir:=Project1.ProjectDirectory;
|
|
SrcFilename:=CreateRelativePath(Project1.MainUnitInfo.Filename,WorkingDir);
|
|
end else begin
|
|
WorkingDir:=GetTestBuildDirectory;
|
|
SrcFilename:=MainBuildBoss.GetTestUnitFilename(Project1.MainUnitInfo);
|
|
end;
|
|
|
|
// compile required packages
|
|
if not (pbfDoNotCompileDependencies in Flags) then begin
|
|
Result:=DoCallModalFunctionHandler(lihtProjectDependenciesCompiling);
|
|
if Result<>mrOk then exit;
|
|
PkgFlags:=[pcfDoNotSaveEditorFiles];
|
|
if pbfCompileDependenciesClean in Flags then
|
|
Include(PkgFlags,pcfCompileDependenciesClean);
|
|
Result:=PkgBoss.DoCompileProjectDependencies(Project1,PkgFlags);
|
|
if Result <> mrOk then
|
|
begin
|
|
CompileProgress.Ready(lisInfoBuildError);
|
|
exit;
|
|
end;
|
|
Result:=DoCallModalFunctionHandler(lihtProjectDependenciesCompiled);
|
|
if Result<>mrOk then exit;
|
|
end;
|
|
|
|
CompilerFilename:=Project1.GetCompilerFilename;
|
|
//DebugLn(['TMainIDE.DoBuildProject CompilerFilename="',CompilerFilename,'" CompilerPath="',Project1.CompilerOptions.CompilerPath,'"']);
|
|
// Note: use absolute paths, because some external tools resolve symlinked directories
|
|
CompilerParams :=
|
|
Project1.CompilerOptions.MakeOptionsString(SrcFilename,[ccloAbsolutePaths])
|
|
+ ' ' + PrepareCmdLineOption(SrcFilename);
|
|
//DebugLn('TMainIDE.DoBuildProject WorkingDir="',WorkingDir,'" SrcFilename="',SrcFilename,'" CompilerFilename="',CompilerFilename,'" CompilerParams="',CompilerParams,'"');
|
|
|
|
// warn for ambiguous files
|
|
Result:=DoWarnAmbiguousFiles;
|
|
if Result<>mrOk then
|
|
begin
|
|
CompileProgress.Ready(lisInfoBuildError);
|
|
exit;
|
|
end;
|
|
|
|
// check if build is needed (only if we will call the compiler)
|
|
// and check if a 'build all' is needed
|
|
NeedBuildAllFlag:=false;
|
|
if (AReason in Project1.CompilerOptions.CompileReasons) then begin
|
|
Result:=DoCheckIfProjectNeedsCompilation(Project1,
|
|
CompilerFilename,CompilerParams,
|
|
SrcFilename,NeedBuildAllFlag);
|
|
if (pbfOnlyIfNeeded in Flags)
|
|
and (not (pfAlwaysBuild in Project1.Flags)) then begin
|
|
if Result=mrNo then begin
|
|
CompileProgress.Ready(lisInfoBuildError);
|
|
Result:=mrOk;
|
|
exit;
|
|
end;
|
|
if Result<>mrYes then
|
|
begin
|
|
CompileProgress.Ready(lisInfoBuildError);
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// create unit output directory
|
|
UnitOutputDirectory:=Project1.CompilerOptions.GetUnitOutPath(false);
|
|
if Project1.IsVirtual and (not FilenameIsAbsolute(UnitOutputDirectory)) then
|
|
UnitOutputDirectory:=TrimFilename(WorkingDir+PathDelim+UnitOutputDirectory);
|
|
if (FilenameIsAbsolute(UnitOutputDirectory))
|
|
and (not DirPathExistsCached(UnitOutputDirectory)) then begin
|
|
if not FileIsInPath(UnitOutputDirectory,WorkingDir) then begin
|
|
Result:=IDEQuestionDialog(lisCreateDirectory,
|
|
Format(lisTheOutputDirectoryIsMissing, ['"', UnitOutputDirectory, '"']
|
|
),
|
|
mtConfirmation, [mrYes, lisCreateIt, mrCancel], '');
|
|
if Result<>mrYes then exit;
|
|
end;
|
|
Result:=ForceDirectoryInteractive(UnitOutputDirectory,[mbRetry]);
|
|
if Result<>mrOk then exit;
|
|
end;
|
|
|
|
// create target output directory
|
|
TargetExeName := Project1.CompilerOptions.CreateTargetFilename(Project1.MainFilename);
|
|
if Project1.IsVirtual and (not FilenameIsAbsolute(TargetExeName)) then
|
|
TargetExeName := EnvironmentOptions.GetTestBuildDirectory + TargetExeName;
|
|
TargetExeDirectory:=ExtractFilePath(TargetExeName);
|
|
if (FilenameIsAbsolute(TargetExeDirectory))
|
|
and (not DirPathExistsCached(TargetExeDirectory)) then begin
|
|
if not FileIsInPath(TargetExeDirectory,WorkingDir) then begin
|
|
Result:=IDEQuestionDialog(lisCreateDirectory,
|
|
Format(lisTheOutputDirectoryIsMissing, ['"', TargetExeDirectory, '"']
|
|
),
|
|
mtConfirmation, [mrYes, lisCreateIt, mrCancel], '');
|
|
if Result<>mrYes then exit;
|
|
end;
|
|
Result:=ForceDirectoryInteractive(TargetExeDirectory,[mbRetry]);
|
|
if Result<>mrOk then exit;
|
|
end;
|
|
|
|
// create application bundle
|
|
if Project1.UseAppBundle and (Project1.MainUnitID>=0)
|
|
and (MainBuildBoss.GetLCLWidgetType=LCLPlatformDirNames[lpCarbon])
|
|
then begin
|
|
Result:=CreateApplicationBundle(TargetExeName, Project1.GetTitleOrName);
|
|
if not (Result in [mrOk,mrIgnore]) then exit;
|
|
Result:=CreateAppBundleSymbolicLink(TargetExeName);
|
|
if not (Result in [mrOk,mrIgnore]) then exit;
|
|
end;
|
|
|
|
if not Project1.ProjResources.Regenerate(Project1.MainFilename, False, True, TargetExeDirectory) then
|
|
Exit;
|
|
|
|
// execute compilation tool 'Before'
|
|
if not (pbfSkipTools in Flags) then begin
|
|
ToolBefore:=TProjectCompilationToolOptions(
|
|
Project1.CompilerOptions.ExecuteBefore);
|
|
if (AReason in ToolBefore.CompileReasons) then begin
|
|
Result:=Project1.CompilerOptions.ExecuteBefore.Execute(
|
|
Project1.ProjectDirectory,lisExecutingCommandBefore);
|
|
if Result<>mrOk then
|
|
begin
|
|
CompileProgress.Ready(lisInfoBuildError);
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if (AReason in Project1.CompilerOptions.CompileReasons)
|
|
and (not (pbfDoNotCompileProject in Flags)) then begin
|
|
try
|
|
// change tool status
|
|
ToolStatus:=itBuilder;
|
|
|
|
ConnectOutputFilter;
|
|
for err := Low(TFPCErrorType) to High(TFPCErrorType) do
|
|
with Project1.CompilerOptions.CompilerMessages do
|
|
TheOutputFilter.ErrorTypeName[err] := ErrorNames[err];
|
|
|
|
// compile
|
|
Result:=TheCompiler.Compile(Project1,
|
|
WorkingDir,CompilerFilename,CompilerParams,
|
|
(pbfCleanCompile in Flags) or NeedBuildAllFlag,
|
|
pbfSkipLinking in Flags,
|
|
pbfSkipAssembler in Flags);
|
|
if Result<>mrOk then begin
|
|
// save state, so that next time the project is not compiled clean
|
|
Project1.LastCompilerFilename:=CompilerFilename;
|
|
Project1.LastCompilerParams:=CompilerParams;
|
|
Project1.LastCompilerFileDate:=FileAgeCached(CompilerFilename);
|
|
DoJumpToCompilerMessage(-1,not EnvironmentOptions.ShowCompileDialog);
|
|
CompileProgress.Ready(lisInfoBuildError);
|
|
exit;
|
|
end;
|
|
// compilation succeded -> write state file
|
|
Result:=Project1.SaveStateFile(CompilerFilename,CompilerParams);
|
|
if Result<>mrOk then begin
|
|
CompileProgress.Ready(lisInfoBuildError);
|
|
exit;
|
|
end;
|
|
|
|
// update project .po file
|
|
Result:=UpdateProjectPOFile(Project1);
|
|
if Result<>mrOk then begin
|
|
CompileProgress.Ready(lisInfoBuildError);
|
|
exit;
|
|
end;
|
|
|
|
finally
|
|
ToolStatus:=itNone;
|
|
end;
|
|
end;
|
|
|
|
// execute compilation tool 'After'
|
|
if not (pbfSkipTools in Flags) then begin
|
|
ToolAfter:=TProjectCompilationToolOptions(
|
|
Project1.CompilerOptions.ExecuteAfter);
|
|
// no need to check for mrOk, we are exit if it wasn't
|
|
if (AReason in ToolAfter.CompileReasons) then begin
|
|
Result:=Project1.CompilerOptions.ExecuteAfter.Execute(
|
|
Project1.ProjectDirectory,lisExecutingCommandAfter);
|
|
if Result<>mrOk then
|
|
begin
|
|
CompileProgress.Ready(lisInfoBuildError);
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Project1.ProjResources.DoAfterBuild(AReason, Project1.IsVirtual);
|
|
// add success message
|
|
MessagesView.AddMsg(Format(lisProjectSuccessfullyBuilt, ['"',
|
|
Project1.ShortDescription, '"']),'',-1);
|
|
CompileProgress.Ready(lisInfoBuildSuccess);
|
|
finally
|
|
// check sources
|
|
DoCheckFilesOnDisk;
|
|
|
|
MessagesView.EndBlock;
|
|
end;
|
|
IDEWindowCreators.ShowForm(MessagesView,EnvironmentOptions.MsgViewFocus);
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoAbortBuild: TModalResult;
|
|
begin
|
|
Result:=mrOk;
|
|
if ToolStatus<>itBuilder then exit;
|
|
TheOutputFilter.StopExecute:=true;
|
|
end;
|
|
|
|
procedure TMainIDE.DoQuickCompile;
|
|
begin
|
|
DoBuildProject(crCompile,[pbfSkipLinking,pbfSkipTools,pbfSkipAssembler]);
|
|
end;
|
|
|
|
function TMainIDE.DoInitProjectRun: TModalResult;
|
|
var
|
|
ProgramFilename: string;
|
|
begin
|
|
if ToolStatus <> itNone
|
|
then begin
|
|
// already running so no initialization needed
|
|
Result := mrOk;
|
|
Exit;
|
|
end;
|
|
|
|
Result := mrCancel;
|
|
|
|
// Check if we can run this project
|
|
debugln('TMainIDE.DoInitProjectRun A ',dbgs(pfRunnable in Project1.Flags),' ',dbgs(Project1.MainUnitID));
|
|
if not ( ((Project1.CompilerOptions.ExecutableType=cetProgram) or
|
|
(Project1.RunParameterOptions.HostApplicationFilename<>''))
|
|
and (pfRunnable in Project1.Flags) and (Project1.MainUnitID >= 0) ) then Exit;
|
|
|
|
debugln('TMainIDE.DoInitProjectRun B');
|
|
// Build project first
|
|
if DoBuildProject(crRun,[pbfOnlyIfNeeded]) <> mrOk then Exit;
|
|
|
|
// Check project build
|
|
ProgramFilename := MainBuildBoss.GetProjectTargetFilename(Project1);
|
|
DebugLn(['TMainIDE.DoInitProjectRun ProgramFilename=',ProgramFilename]);
|
|
if not FileExistsUTF8(ProgramFilename)
|
|
then begin
|
|
MessageDlg(lisFileNotFound,
|
|
Format(lisNoProgramFileSFound, ['"', ProgramFilename, '"']),
|
|
mtError,[mbCancel], 0);
|
|
Exit;
|
|
end;
|
|
|
|
// Setup debugger
|
|
if not DebugBoss.InitDebugger then Exit;
|
|
|
|
Result := mrOK;
|
|
ToolStatus := itDebugger;
|
|
end;
|
|
|
|
function TMainIDE.DoRunProject: TModalResult;
|
|
begin
|
|
DebugLn('[TMainIDE.DoRunProject] A');
|
|
|
|
if (DoInitProjectRun <> mrOK)
|
|
or (ToolStatus <> itDebugger)
|
|
then begin
|
|
Result := mrAbort;
|
|
Exit;
|
|
end;
|
|
debugln('[TMainIDE.DoRunProject] B ',EnvironmentOptions.DebuggerConfig.DebuggerClass);
|
|
|
|
Result := mrCancel;
|
|
|
|
Result := DebugBoss.StartDebugging;
|
|
if Result = mrOk then
|
|
CompileProgress.Hide();
|
|
|
|
DebugLn('[TMainIDE.DoRunProject] END');
|
|
end;
|
|
|
|
function TMainIDE.SomethingOfProjectIsModified(Verbose: boolean): boolean;
|
|
begin
|
|
Result:=(Project1<>nil)
|
|
and (Project1.SomethingModified(true,true,Verbose)
|
|
or SourceEditorManager.SomethingModified(Verbose));
|
|
end;
|
|
|
|
function TMainIDE.DoSaveAll(Flags: TSaveFlags): TModalResult;
|
|
var
|
|
CurResult: TModalResult;
|
|
begin
|
|
Result:=mrOk;
|
|
CurResult:=DoCallModalFunctionHandler(lihtSavingAll);
|
|
if CurResult=mrAbort then exit(mrAbort);
|
|
if CurResult<>mrOk then Result:=mrCancel;
|
|
CurResult:=DoSaveProject(Flags);
|
|
SaveEnvironment;
|
|
SaveIncludeLinks;
|
|
PkgBoss.SaveSettings;
|
|
InputHistories.Save;
|
|
if CurResult=mrAbort then exit(mrAbort);
|
|
if CurResult<>mrOk then Result:=mrCancel;
|
|
CurResult:=DoCallModalFunctionHandler(lihtSavedAll);
|
|
if CurResult=mrAbort then exit(mrAbort);
|
|
if CurResult<>mrOk then Result:=mrCancel;
|
|
UpdateSaveMenuItemsAndButtons(true);
|
|
end;
|
|
|
|
procedure TMainIDE.DoRestart;
|
|
|
|
const
|
|
DarwinStartlazBundlePath = 'Resources/startlazarus.app/Contents/MacOS/';
|
|
|
|
procedure StartStarter;
|
|
var
|
|
StartLazProcess : TProcessUTF8;
|
|
ExeName : string;
|
|
Params : TStrings;
|
|
Dummy : Integer;
|
|
Unused : boolean;
|
|
CmdLine: string;
|
|
begin
|
|
StartLazProcess := TProcessUTF8.Create(nil);
|
|
try
|
|
// TODO: use the target directory, where the new startlazarus is
|
|
StartLazProcess.CurrentDirectory := GetLazarusDirectory;
|
|
//DebugLn('Parsing commandLine: ');
|
|
Params := TStringList.Create;
|
|
ParseCommandLine(Params, Dummy, Unused);
|
|
//DebugLn('Done parsing CommandLine');
|
|
{$ifndef darwin}
|
|
ExeName := AppendPathDelim(StartLazProcess.CurrentDirectory) +
|
|
'startlazarus' + GetExecutableExt;
|
|
{$else}
|
|
ExeName := ExpandUNCFileNameUTF8(StartLazProcess.CurrentDirectory);
|
|
ExeName := AppendPathDelim( ExtractFilePath(ExeName) ) +
|
|
DarwinStartlazBundlePath + 'startlazarus' + GetExecutableExt;
|
|
{$endif}
|
|
if not FileExistsUTF8(ExeName) then begin
|
|
IDEMessageDialog('Error',Format(lisCannotFindLazarusStarter,
|
|
[LineEnding, ExeName]),mtError,[mbCancel]);
|
|
exit;
|
|
end;
|
|
//DebugLn('Setting CommandLine');
|
|
CmdLine := ExeName +
|
|
' --lazarus-pid='+IntToStr(GetProcessID) + ' ' +
|
|
GetCommandLineParameters(Params, False);
|
|
|
|
DebugLn('CommandLine 1 : %s', [CmdLine]);
|
|
|
|
if (pos(PrimaryConfPathOptLong, CmdLine) = 0) and
|
|
(pos(PrimaryConfPathOptShort, CmdLine) = 0) then
|
|
CmdLine := CmdLine + ' "' + PrimaryConfPathOptLong + GetPrimaryConfigPath+'"';
|
|
|
|
DebugLn('CommandLine 2 : %s', [CmdLine]);
|
|
StartLazProcess.CommandLine := CmdLine;
|
|
StartLazProcess.Execute;
|
|
finally
|
|
FreeAndNil(Params);
|
|
StartLazProcess.Free;
|
|
end;
|
|
end;
|
|
|
|
var CanClose: boolean;
|
|
begin
|
|
DebugLn(['TMainIDE.DoRestart ']);
|
|
CanClose:=true;
|
|
MainIDEBar.OnCloseQuery(Self, CanClose);
|
|
if not CanClose then exit;
|
|
MainIDEBar.Close;
|
|
if Application.Terminated then begin
|
|
if StartedByStartLazarus then
|
|
ExitCode := ExitCodeRestartLazarus
|
|
else
|
|
StartStarter;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.DoExecuteRemoteControl;
|
|
|
|
procedure OpenFiles(Files: TStrings);
|
|
var
|
|
AProjectFilename: string;
|
|
ProjectLoaded: Boolean;
|
|
AFilename: String;
|
|
i: Integer;
|
|
OpenFlags: TOpenFlags;
|
|
begin
|
|
if (Files=nil) or (Files.Count=0) then exit;
|
|
ProjectLoaded:=Project1<>nil;
|
|
DebugLn(['TMainIDE.DoExecuteRemoteControl.OpenFiles ProjectLoaded=',ProjectLoaded]);
|
|
|
|
// open project (only the last in the list)
|
|
AProjectFilename:='';
|
|
for i:=Files.Count-1 downto 0 do begin
|
|
AProjectFilename:=Files[0];
|
|
if (CompareFileExt(AProjectFilename,'.lpr',false)=0) then
|
|
AProjectFilename:=ChangeFileExt(AProjectFilename,'.lpi');
|
|
if (CompareFileExt(AProjectFilename,'.lpi',false)=0) then begin
|
|
// open a project
|
|
Files.Delete(i); // remove from the list
|
|
AProjectFilename:=CleanAndExpandFilename(AProjectFilename);
|
|
if FileExistsUTF8(AProjectFilename) then begin
|
|
DebugLn(['TMainIDE.DoExecuteRemoteControl.OpenFiles AProjectFilename="',AProjectFilename,'"']);
|
|
if (Project1<>nil)
|
|
and (CompareFilenames(AProjectFilename,Project1.ProjectInfoFile)=0)
|
|
then begin
|
|
// project is already open => do not reopen
|
|
ProjectLoaded:=true;
|
|
end else begin
|
|
// open another project
|
|
ProjectLoaded:=(DoOpenProjectFile(AProjectFilename,[])=mrOk);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if not ProjectLoaded then begin
|
|
// create new project
|
|
DoNewProject(ProjectDescriptorApplication);
|
|
end;
|
|
|
|
// load the files
|
|
if Files<>nil then begin
|
|
for i:=0 to Files.Count-1 do begin
|
|
AFilename:=CleanAndExpandFilename(Files.Strings[i]);
|
|
DebugLn(['TMainIDE.DoExecuteRemoteControl.OpenFiles AFilename="',AFilename,'"']);
|
|
if CompareFileExt(AFilename,'.lpk',false)=0 then begin
|
|
if PkgBoss.DoOpenPackageFile(AFilename,[pofAddToRecent],true)=mrAbort
|
|
then
|
|
break;
|
|
end else begin
|
|
OpenFlags:=[ofAddToRecent,ofRegularFile];
|
|
if i<Files.Count then
|
|
Include(OpenFlags,ofMultiOpen);
|
|
if DoOpenEditorFile(AFilename,-1,-1,OpenFlags)=mrAbort then begin
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
Filename: String;
|
|
List: TStringList;
|
|
Files: TStrings;
|
|
i: Integer;
|
|
CmdShow: Boolean;
|
|
begin
|
|
Filename:=GetRemoteControlFilename;
|
|
if FileExistsUTF8(Filename) and (FRemoteControlFileAge<>FileAgeUTF8(Filename))
|
|
then begin
|
|
// the control file exists and has changed
|
|
List:=TStringList.Create;
|
|
Files:=nil;
|
|
try
|
|
// load and delete the file
|
|
try
|
|
List.LoadFromFile(UTF8ToSys(Filename));
|
|
except
|
|
DebugLn(['TMainIDE.DoExecuteRemoteControl reading file failed: ',Filename]);
|
|
end;
|
|
DeleteFileUTF8(Filename);
|
|
FRemoteControlFileAge:=-1;
|
|
// execute
|
|
Files:=TStringList.Create;
|
|
CmdShow:=false;
|
|
for i:=0 to List.Count-1 do begin
|
|
if SysUtils.CompareText(List[i],'show')=0 then
|
|
CmdShow:=true;
|
|
if SysUtils.CompareText(copy(List[i],1,5),'open ')=0 then
|
|
Files.Add(copy(List[i],6,length(List[i])));
|
|
end;
|
|
if CmdShow then begin
|
|
// if minimized then restore, bring IDE to front
|
|
Application.MainForm.ShowOnTop;
|
|
end;
|
|
if Files.Count>0 then begin
|
|
OpenFiles(Files);
|
|
end;
|
|
finally
|
|
List.Free;
|
|
Files.Free;
|
|
end;
|
|
end else begin
|
|
// the control file does not exist
|
|
FRemoteControlFileAge:=-1;
|
|
end;
|
|
end;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function TMainIDE.DoRunExternalTool(Index: integer; ShowAbort: Boolean
|
|
): TModalResult;
|
|
begin
|
|
SourceEditorManager.ClearErrorLines;
|
|
Result:=ExternalTools.Run(Index,GlobalMacroList,ShowAbort);
|
|
DoCheckFilesOnDisk;
|
|
end;
|
|
|
|
function TMainIDE.DoSaveBuildIDEConfigs(Flags: TBuildLazarusFlags): TModalResult;
|
|
var
|
|
PkgOptions: string;
|
|
InheritedOptionStrings: TInheritedCompOptsStrings;
|
|
FPCVersion, FPCRelease, FPCPatch: integer;
|
|
IDEBuildFlags: TBuildLazarusFlags;
|
|
begin
|
|
// create uses section addition for lazarus.pp
|
|
Result:=PkgBoss.DoSaveAutoInstallConfig;
|
|
if Result<>mrOk then exit;
|
|
|
|
// prepare static auto install packages
|
|
PkgOptions:='';
|
|
// create inherited compiler options
|
|
PkgOptions:=PackageGraph.GetIDEInstallPackageOptions(
|
|
PackageGraph.FirstAutoInstallDependency,InheritedOptionStrings);
|
|
|
|
// check ambiguous units
|
|
CodeToolBoss.GetFPCVersionForDirectory(
|
|
EnvironmentOptions.LazarusDirectory,
|
|
FPCVersion,FPCRelease,FPCPatch);
|
|
if (FPCVersion=0) or (FPCRelease=0) or (FPCPatch=0) then ;
|
|
|
|
// save extra options
|
|
IDEBuildFlags:=Flags+[blfOnlyIDE];
|
|
Result:=SaveIDEMakeOptions(MiscellaneousOptions.BuildLazProfiles,
|
|
GlobalMacroList,PkgOptions,IDEBuildFlags);
|
|
if Result<>mrOk then exit;
|
|
end;
|
|
|
|
function TMainIDE.DoManageExamples: TModalResult;
|
|
begin
|
|
Result:=ShowManageExamplesDlg;
|
|
end;
|
|
|
|
function TMainIDE.DoBuildLazarusSub(Flags: TBuildLazarusFlags): TModalResult;
|
|
var
|
|
PkgOptions: string;
|
|
IDEBuildFlags: TBuildLazarusFlags;
|
|
InheritedOptionStrings: TInheritedCompOptsStrings;
|
|
CompiledUnitExt: String;
|
|
FPCVersion, FPCRelease, FPCPatch: integer;
|
|
begin
|
|
if ToolStatus<>itNone then begin
|
|
MessageDlg(lisNotNow,
|
|
lisYouCanNotBuildLazarusWhileDebuggingOrCompiling,
|
|
mtError,[mbCancel],0);
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
|
|
Result:=DoSaveAll([sfDoNotSaveVirtualFiles]);
|
|
if Result<>mrOk then begin
|
|
DebugLn('TMainIDE.DoBuildLazarus: failed because saving failed');
|
|
exit;
|
|
end;
|
|
|
|
MessagesView.BeginBlock;
|
|
try
|
|
MainBuildBoss.SetBuildTargetIDE;
|
|
|
|
if (blfOnlyIDE in Flags)
|
|
and (MiscellaneousOptions.BuildLazProfiles.CurrentIdeMode=mmNone) then begin
|
|
debugln(['TMainIDE.DoBuildLazarusSub ignore because blfOnlyIDE and CurrentIdeMode=mmNone']);
|
|
CompileProgress.Ready;
|
|
Result:=mrIgnore;
|
|
exit;
|
|
end;
|
|
|
|
// clean up
|
|
if (not (blfDontCleanAll in Flags))
|
|
and MiscellaneousOptions.BuildLazProfiles.Current.CleanAll then begin
|
|
SourceEditorManager.ClearErrorLines;
|
|
Result:=BuildLazarus(MiscellaneousOptions.BuildLazProfiles,
|
|
ExternalTools,GlobalMacroList,
|
|
'',EnvironmentOptions.GetCompilerFilename,
|
|
EnvironmentOptions.MakeFilename,
|
|
[blfDontBuild]);
|
|
if Result<>mrOk then begin
|
|
DebugLn('TMainIDE.DoBuildLazarus: Clean up failed.');
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
// compile auto install static packages
|
|
Result:=PkgBoss.DoCompileAutoInstallPackages([],false);
|
|
if Result<>mrOk then begin
|
|
DebugLn('TMainIDE.DoBuildLazarus: Compile AutoInstall Packages failed.');
|
|
exit;
|
|
end;
|
|
|
|
// create uses section addition for lazarus.pp
|
|
Result:=PkgBoss.DoSaveAutoInstallConfig;
|
|
if Result<>mrOk then begin
|
|
DebugLn('TMainIDE.DoBuildLazarus: Save AutoInstall Config failed.');
|
|
exit;
|
|
end;
|
|
|
|
// create inherited compiler options
|
|
PkgOptions:=PackageGraph.GetIDEInstallPackageOptions(
|
|
PackageGraph.FirstAutoInstallDependency,InheritedOptionStrings);
|
|
|
|
// check ambiguous units
|
|
CodeToolBoss.GetFPCVersionForDirectory(
|
|
EnvironmentOptions.LazarusDirectory,
|
|
FPCVersion,FPCRelease,FPCPatch);
|
|
if FPCPatch=0 then ;
|
|
CompiledUnitExt:=GetDefaultCompiledUnitExt(FPCVersion,FPCRelease);
|
|
Result:=MainBuildBoss.CheckUnitPathForAmbiguousPascalFiles(
|
|
EnvironmentOptions.LazarusDirectory+PathDelim+'ide',
|
|
InheritedOptionStrings[icoUnitPath],
|
|
CompiledUnitExt,'IDE');
|
|
if Result<>mrOk then begin
|
|
DebugLn('TMainIDE.DoBuildLazarus: Check UnitPath for ambiguous pascal files failed.');
|
|
exit;
|
|
end;
|
|
|
|
// save extra options
|
|
IDEBuildFlags:=Flags;
|
|
if MiscellaneousOptions.BuildLazProfiles.Current.CleanAll then
|
|
Include(IDEBuildFlags,blfDontCleanAll);
|
|
if MiscellaneousOptions.BuildLazProfiles.CurrentIdeMode<>mmNone then begin
|
|
Result:=SaveIDEMakeOptions(MiscellaneousOptions.BuildLazProfiles,
|
|
GlobalMacroList,PkgOptions,IDEBuildFlags-[blfUseMakeIDECfg]);
|
|
if Result<>mrOk then begin
|
|
DebugLn('TMainIDE.DoBuildLazarus: Save IDEMake options failed.');
|
|
exit;
|
|
end;
|
|
IDEBuildFlags:=IDEBuildFlags+[blfUseMakeIDECfg];
|
|
end;
|
|
|
|
// make lazarus ide and/or examples
|
|
SourceEditorManager.ClearErrorLines;
|
|
Result:=BuildLazarus(MiscellaneousOptions.BuildLazProfiles,
|
|
ExternalTools,GlobalMacroList,
|
|
PkgOptions,EnvironmentOptions.GetCompilerFilename,
|
|
EnvironmentOptions.MakeFilename,
|
|
IDEBuildFlags);
|
|
if Result<>mrOk then exit;
|
|
|
|
finally
|
|
MainBuildBoss.SetBuildTargetProject1(true);
|
|
|
|
DoCheckFilesOnDisk;
|
|
MessagesView.EndBlock;
|
|
|
|
if Result in [mrOK, mrIgnore] then
|
|
CompileProgress.Ready(lisinfoBuildSuccess)
|
|
else
|
|
CompileProgress.Ready(lisInfoBuildError);
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.ExternalTools: TExternalToolList;
|
|
begin
|
|
Result:=TExternalToolList(EnvironmentOptions.ExternalTools);
|
|
end;
|
|
|
|
function TMainIDE.DoBuildLazarus(Flags: TBuildLazarusFlags): TModalResult;
|
|
begin
|
|
Result:=DoBuildLazarusSub(Flags);
|
|
with MiscellaneousOptions do
|
|
if (Result=mrOK) then begin
|
|
if BuildLazProfiles.RestartAfterBuild
|
|
and (BuildLazProfiles.Current.TargetDirectory='')
|
|
and MainBuildBoss.BuildTargetIDEIsDefault
|
|
then begin
|
|
CompileProgress.Close;
|
|
mnuRestartClicked(nil);
|
|
end
|
|
end
|
|
else if Result=mrIgnore then
|
|
Result:=mrOK;
|
|
end;
|
|
|
|
function TMainIDE.DoBuildAdvancedLazarus(ProfileNames: TStringList): TModalResult;
|
|
var
|
|
CmdLineDefines: TDefineTemplate;
|
|
LazSrcTemplate: TDefineTemplate;
|
|
LazSrcDirTemplate: TDefineTemplate;
|
|
i, ProfInd, RealCurInd: Integer;
|
|
MayNeedRestart: Boolean;
|
|
begin
|
|
Result:=mrOK;
|
|
with MiscellaneousOptions do begin
|
|
MayNeedRestart:=False;
|
|
RealCurInd:=BuildLazProfiles.CurrentIndex;
|
|
try
|
|
for i:=0 to ProfileNames.Count-1 do begin
|
|
ProfInd:=BuildLazProfiles.IndexByName(ProfileNames[i]);
|
|
if ProfInd<>-1 then begin
|
|
// Set current profile temporarily, used by the codetools functions.
|
|
BuildLazProfiles.CurrentIndex:=ProfInd;
|
|
// does not show message: IDEMessagesWindow.AddMsg('Building: '+BuildLazProfiles.Current.Name,'',-1);
|
|
LazSrcTemplate:=
|
|
CodeToolBoss.DefineTree.FindDefineTemplateByName(StdDefTemplLazarusSources,true);
|
|
if Assigned(LazSrcTemplate) then begin
|
|
LazSrcDirTemplate:=LazSrcTemplate.FindChildByName(StdDefTemplLazarusSrcDir);
|
|
if Assigned(LazSrcDirTemplate) then begin
|
|
CmdLineDefines:=CodeToolBoss.DefinePool.CreateFPCCommandLineDefines(
|
|
StdDefTemplLazarusBuildOpts,
|
|
BuildLazProfiles.Current.ExtraOptions,true,CodeToolsOpts);
|
|
CodeToolBoss.DefineTree.ReplaceChild(LazSrcDirTemplate,CmdLineDefines,
|
|
StdDefTemplLazarusBuildOpts);
|
|
end;
|
|
end;
|
|
Result:=DoBuildLazarusSub([]);
|
|
if (Result=mrOK) then begin
|
|
if BuildLazProfiles.RestartAfterBuild
|
|
and (BuildLazProfiles.Current.TargetDirectory='')
|
|
and MainBuildBoss.BuildTargetIDEIsDefault then
|
|
MayNeedRestart:=True
|
|
end
|
|
else if Result=mrIgnore then
|
|
Result:=mrOK
|
|
else
|
|
exit;
|
|
end;
|
|
end;
|
|
finally
|
|
BuildLazProfiles.CurrentIndex:=RealCurInd;
|
|
end;
|
|
if MayNeedRestart and BuildLazProfiles.RestartAfterBuild then begin
|
|
CompileProgress.Close;
|
|
mnuRestartClicked(nil);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoBuildFile(ShowAbort: Boolean): TModalResult;
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
DirectiveList: TStringList;
|
|
BuildWorkingDir: String;
|
|
BuildCommand: String;
|
|
BuildScan: TIDEDirBuildScanFlags;
|
|
ProgramFilename: string;
|
|
Params: string;
|
|
ExtTool: TExternalToolOptions;
|
|
Filename: String;
|
|
begin
|
|
Result:=mrCancel;
|
|
if ToolStatus<>itNone then exit;
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
Result:=DoSaveProject([]);
|
|
if Result<>mrOk then exit;
|
|
DirectiveList:=TStringList.Create;
|
|
try
|
|
Result:=GetIDEDirectives(ActiveUnitInfo,DirectiveList);
|
|
if Result<>mrOk then exit;
|
|
|
|
// get values form directive list
|
|
// build
|
|
BuildWorkingDir:=GetIDEStringDirective(DirectiveList,
|
|
IDEDirectiveNames[idedBuildWorkingDir],
|
|
'');
|
|
if BuildWorkingDir='' then
|
|
BuildWorkingDir:=ExtractFilePath(ActiveUnitInfo.Filename);
|
|
if not GlobalMacroList.SubstituteStr(BuildWorkingDir) then begin
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
BuildCommand:=GetIDEStringDirective(DirectiveList,
|
|
IDEDirectiveNames[idedBuildCommand],
|
|
IDEDirDefaultBuildCommand);
|
|
if (not GlobalMacroList.SubstituteStr(BuildCommand))
|
|
or (BuildCommand='') then begin
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
BuildScan:=GetIDEDirBuildScanFromString(GetIDEStringDirective(DirectiveList,
|
|
IDEDirectiveNames[idedBuildScan],''));
|
|
|
|
SourceEditorManager.ClearErrorLines;
|
|
|
|
SplitCmdLine(BuildCommand,ProgramFilename,Params);
|
|
if not FilenameIsAbsolute(ProgramFilename) then begin
|
|
Filename:=FindProgram(ProgramFilename,BuildWorkingDir,true);
|
|
if Filename<>'' then ProgramFilename:=Filename;
|
|
end;
|
|
if ProgramFilename='' then begin
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
|
|
ExtTool:=TExternalToolOptions.Create;
|
|
try
|
|
ExtTool.Filename:=ProgramFilename;
|
|
ExtTool.ScanOutputForFPCMessages:=idedbsfFPC in BuildScan;
|
|
ExtTool.ScanOutputForMakeMessages:=idedbsfMake in BuildScan;
|
|
ExtTool.ScanOutput:=true;
|
|
ExtTool.Title:='Build File '+ActiveUnitInfo.Filename;
|
|
ExtTool.WorkingDirectory:=BuildWorkingDir;
|
|
ExtTool.CmdLineParams:=Params;
|
|
|
|
// run
|
|
Result:=ExternalTools.Run(ExtTool,GlobalMacroList,true);
|
|
finally
|
|
// clean up
|
|
ExtTool.Free;
|
|
end;
|
|
finally
|
|
DirectiveList.Free;
|
|
end;
|
|
Result:=mrOk;
|
|
|
|
{if AReason <> crRun then
|
|
CompileProgress.Ready
|
|
else}
|
|
CompileProgress.Close;
|
|
end;
|
|
|
|
function TMainIDE.DoRunFile: TModalResult;
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
FirstLine: String;
|
|
HasShebang: Boolean;
|
|
RunFlags: TIDEDirRunFlags;
|
|
DefRunFlags: TIDEDirRunFlags;
|
|
AlwaysBuildBeforeRun: boolean;
|
|
RunWorkingDir: String;
|
|
DefRunCommand: String;
|
|
RunCommand: String;
|
|
ProgramFilename: string;
|
|
Params: string;
|
|
ExtTool: TExternalToolOptions;
|
|
Filename: String;
|
|
DirectiveList: TStringList;
|
|
begin
|
|
Result:=mrCancel;
|
|
if ToolStatus<>itNone then exit;
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
if not FilenameIsAbsolute(ActiveUnitInfo.Filename) then begin
|
|
Result:=DoSaveEditorFile(ActiveSrcEdit,[sfCheckAmbiguousFiles]);
|
|
if Result<>mrOk then exit;
|
|
end;
|
|
DirectiveList:=TStringList.Create;
|
|
try
|
|
Result:=GetIDEDirectives(ActiveUnitInfo,DirectiveList);
|
|
if Result<>mrOk then exit;
|
|
|
|
if ActiveUnitInfo.Source.LineCount>0 then
|
|
FirstLine:=ActiveUnitInfo.Source.GetLine(0)
|
|
else
|
|
FirstLine:='';
|
|
HasShebang:=copy(FirstLine,1,2)='#!';
|
|
DefRunFlags:=IDEDirRunFlagDefValues;
|
|
if HasShebang then Exclude(DefRunFlags,idedrfBuildBeforeRun);
|
|
RunFlags:=GetIDEDirRunFlagFromString(
|
|
GetIDEStringDirective(DirectiveList,IDEDirectiveNames[idedRunFlags],''),
|
|
DefRunFlags);
|
|
AlwaysBuildBeforeRun:=idedrfBuildBeforeRun in RunFlags;
|
|
if AlwaysBuildBeforeRun then begin
|
|
Result:=DoBuildFile(true);
|
|
if Result<>mrOk then exit;
|
|
end;
|
|
RunWorkingDir:=GetIDEStringDirective(DirectiveList,
|
|
IDEDirectiveNames[idedRunWorkingDir],'');
|
|
if RunWorkingDir='' then
|
|
RunWorkingDir:=ExtractFilePath(ActiveUnitInfo.Filename);
|
|
if not GlobalMacroList.SubstituteStr(RunWorkingDir) then begin
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
if HasShebang then
|
|
DefRunCommand:='instantfpc'+ExeExt+' '+ActiveUnitInfo.Filename
|
|
else
|
|
DefRunCommand:=IDEDirDefaultRunCommand;
|
|
RunCommand:=GetIDEStringDirective(DirectiveList,
|
|
IDEDirectiveNames[idedRunCommand],
|
|
DefRunCommand);
|
|
if (not GlobalMacroList.SubstituteStr(RunCommand)) then
|
|
exit(mrCancel);
|
|
if (RunCommand='') then
|
|
exit(mrCancel);
|
|
|
|
SourceEditorManager.ClearErrorLines;
|
|
|
|
SplitCmdLine(RunCommand,ProgramFilename,Params);
|
|
if not FilenameIsAbsolute(ProgramFilename) then begin
|
|
Filename:=FindProgram(ProgramFilename,RunWorkingDir,true);
|
|
if Filename<>'' then ProgramFilename:=Filename;
|
|
end;
|
|
if ProgramFilename='' then begin
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
|
|
ExtTool:=TExternalToolOptions.Create;
|
|
try
|
|
ExtTool.Filename:=ProgramFilename;
|
|
ExtTool.Title:='Run File '+ActiveUnitInfo.Filename;
|
|
ExtTool.WorkingDirectory:=RunWorkingDir;
|
|
ExtTool.CmdLineParams:=Params;
|
|
|
|
// run
|
|
Result:=ExternalTools.Run(ExtTool,GlobalMacroList,false);
|
|
finally
|
|
// clean up
|
|
ExtTool.Free;
|
|
end;
|
|
finally
|
|
DirectiveList.Free;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoConfigBuildFile: TModalResult;
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
DirectiveList: TStringList;
|
|
CodeResult: Boolean;
|
|
BuildFileDialog: TBuildFileDialog;
|
|
s: String;
|
|
begin
|
|
Result:=mrCancel;
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
if not FilenameIsAbsolute(ActiveUnitInfo.Filename) then begin
|
|
Result:=DoSaveEditorFile(ActiveSrcEdit,[sfCheckAmbiguousFiles]);
|
|
if Result<>mrOk then exit;
|
|
end;
|
|
DirectiveList:=TStringList.Create;
|
|
try
|
|
Result:=GetIDEDirectives(ActiveUnitInfo,DirectiveList);
|
|
if Result<>mrOk then exit;
|
|
|
|
BuildFileDialog:=TBuildFileDialog.Create(nil);
|
|
try
|
|
BuildFileDialog.DirectiveList:=DirectiveList;
|
|
BuildFileDialog.BuildFileIfActive:=ActiveUnitInfo.BuildFileIfActive;
|
|
BuildFileDialog.RunFileIfActive:=ActiveUnitInfo.RunFileIfActive;
|
|
BuildFileDialog.MacroList:=GlobalMacroList;
|
|
BuildFileDialog.Filename:=
|
|
CreateRelativePath(ActiveUnitInfo.Filename,Project1.ProjectDirectory);
|
|
if BuildFileDialog.ShowModal<>mrOk then begin
|
|
DebugLn(['TMainIDE.DoConfigBuildFile cancelled']);
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
ActiveUnitInfo.BuildFileIfActive:=BuildFileDialog.BuildFileIfActive;
|
|
ActiveUnitInfo.RunFileIfActive:=BuildFileDialog.RunFileIfActive;
|
|
finally
|
|
BuildFileDialog.Free;
|
|
end;
|
|
|
|
//DebugLn(['TMainIDE.DoConfigBuildFile ',ActiveUnitInfo.Filename,' ',DirectiveList.DelimitedText]);
|
|
|
|
// save IDE directives
|
|
if FilenameIsPascalSource(ActiveUnitInfo.Filename) then begin
|
|
// parse source for IDE directives (i.e. % comments)
|
|
CodeResult:=CodeToolBoss.SetIDEDirectives(ActiveUnitInfo.Source,
|
|
DirectiveList);
|
|
ApplyCodeToolChanges;
|
|
if not CodeResult then begin
|
|
DoJumpToCodeToolBossError;
|
|
exit;
|
|
end;
|
|
|
|
end else begin
|
|
s:=StringListToString(DirectiveList,0,DirectiveList.Count-1,true);
|
|
if ActiveUnitInfo.CustomData['IDEDirectives']<>s then begin
|
|
ActiveUnitInfo.CustomData['IDEDirectives']:=s;
|
|
ActiveUnitInfo.Modified:=true;
|
|
end;
|
|
end;
|
|
|
|
finally
|
|
DirectiveList.Free;
|
|
end;
|
|
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.GetIDEDirectives(AnUnitInfo: TUnitInfo;
|
|
DirectiveList: TStrings): TModalResult;
|
|
var
|
|
CodeResult: Boolean;
|
|
begin
|
|
Result:=mrCancel;
|
|
if FilenameIsPascalSource(AnUnitInfo.Filename) then begin
|
|
// parse source for IDE directives (i.e. % comments)
|
|
CodeResult:=CodeToolBoss.GetIDEDirectives(AnUnitInfo.Source,DirectiveList);
|
|
if not CodeResult then begin
|
|
DoJumpToCodeToolBossError;
|
|
exit;
|
|
end;
|
|
end else begin
|
|
StringToStringList(AnUnitInfo.CustomData['IDEDirectives'],DirectiveList);
|
|
//DebugLn(['TMainIDE.GetIDEDirectives ',dbgstr(DirectiveList.Text)]);
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoConvertDFMtoLFM: TModalResult;
|
|
var
|
|
OpenDialog: TOpenDialog;
|
|
DFMConverter: TDFMConverter;
|
|
i: integer;
|
|
AFilename: string;
|
|
begin
|
|
Result:=mrOk;
|
|
OpenDialog:=TOpenDialog.Create(nil);
|
|
try
|
|
InputHistories.ApplyFileDialogSettings(OpenDialog);
|
|
OpenDialog.Title:=lisSelectDFMFiles;
|
|
OpenDialog.Options:=OpenDialog.Options+[ofAllowMultiSelect];
|
|
OpenDialog.Filter:=rsFormDataFileDfm+'|'+dlgAllFiles+'|'+GetAllFilesMask;
|
|
if OpenDialog.Execute and (OpenDialog.Files.Count>0) then begin
|
|
For I := 0 to OpenDialog.Files.Count-1 do begin
|
|
AFilename:=ExpandFileNameUTF8(OpenDialog.Files.Strings[i]);
|
|
DFMConverter:=TDFMConverter.Create(nil);
|
|
try
|
|
Result:=DFMConverter.Convert(AFilename);
|
|
finally
|
|
DFMConverter.Free;
|
|
end;
|
|
end;
|
|
SaveEnvironment;
|
|
end;
|
|
InputHistories.StoreFileDialogSettings(OpenDialog);
|
|
finally
|
|
OpenDialog.Free;
|
|
end;
|
|
DoCheckFilesOnDisk;
|
|
end;
|
|
|
|
function TMainIDE.DoCheckLFMInEditor(Quiet: boolean): TModalResult;
|
|
var
|
|
LFMChecker: TLFMChecker;
|
|
LFMSrcEdit: TSourceEditor;
|
|
LFMUnitInfo: TUnitInfo;
|
|
UnitFilename: String;
|
|
PascalBuf: TCodeBuffer;
|
|
i: integer;
|
|
begin
|
|
// check, if a .lfm file is opened in the source editor
|
|
GetCurrentUnit(LFMSrcEdit,LFMUnitInfo);
|
|
if (LFMUnitInfo=nil) or
|
|
((CompareFileExt(LFMUnitInfo.Filename,'.lfm',false)<>0) and
|
|
(CompareFileExt(LFMUnitInfo.Filename,'.dfm',false)<>0)) then
|
|
begin
|
|
if not Quiet then
|
|
begin
|
|
MessageDlg(lisNoLFMFile,
|
|
lisThisFunctionNeedsAnOpenLfmFileInTheSourceEditor,
|
|
mtError,[mbCancel],0);
|
|
end;
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
// try to find the pascal unit
|
|
for i:=Low(PascalFileExt) to High(PascalFileExt) do begin
|
|
UnitFilename:=ChangeFileExt(LFMUnitInfo.Filename,PascalFileExt[i]);
|
|
if FileExistsUTF8(UnitFilename) then
|
|
break
|
|
else
|
|
UnitFilename:='';
|
|
end;
|
|
if UnitFilename='' then begin
|
|
MessageDlg(lisNoPascalFile,
|
|
Format(lisUnableToFindPascalUnitPasPpForLfmFile, [#13, '"',
|
|
LFMUnitInfo.Filename, '"']),
|
|
mtError,[mbCancel],0);
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
|
|
if ToolStatus<>itNone then begin
|
|
DebugLn(['TMainIDE.DoCheckLFMInEditor ToolStatus<>itNone']);
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
// load the pascal unit
|
|
SaveSourceEditorChangesToCodeCache(nil);
|
|
Result:=LoadCodeBuffer(PascalBuf,UnitFilename,[],false);
|
|
if Result<>mrOk then exit;
|
|
|
|
// open messages window
|
|
SourceEditorManager.ClearErrorLines;
|
|
if MessagesView<>nil then
|
|
MessagesView.Clear;
|
|
DoArrangeSourceEditorAndMessageView(false);
|
|
|
|
// parse the LFM file and the pascal unit
|
|
LFMChecker:=TLFMChecker.Create(PascalBuf,LFMUnitInfo.Source,@MessagesView.AddMsg);
|
|
try
|
|
LFMChecker.RootMustBeClassInUnit:=true;
|
|
LFMChecker.RootMustBeClassInIntf:=true;
|
|
LFMChecker.ObjectsMustExists:=true;
|
|
if LFMChecker.Repair=mrOk then begin
|
|
if not Quiet then begin
|
|
IDEMessageDialog(lisLFMIsOk,
|
|
lisClassesAndPropertiesExistValuesWereNotChecked,
|
|
mtInformation,[mbOk],'');
|
|
end;
|
|
end else begin
|
|
DoJumpToCompilerMessage(-1,true);
|
|
Result:=mrAbort;
|
|
exit;
|
|
end;
|
|
finally
|
|
LFMChecker.Free;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TMainIDE.DoConvertDelphiUnit(const DelphiFilename: string;
|
|
CanAbort: boolean): TModalResult;
|
|
var
|
|
OldChange: Boolean;
|
|
Converter: TConvertDelphiUnit;
|
|
begin
|
|
InputHistories.LastConvertDelphiUnit:=DelphiFilename;
|
|
OldChange:=OpenEditorsOnCodeToolChange;
|
|
OpenEditorsOnCodeToolChange:=true;
|
|
Converter := TConvertDelphiUnit.Create(nil, DelphiFilename, []);
|
|
try
|
|
Result:=Converter.Convert;
|
|
finally
|
|
Converter.Free;
|
|
OpenEditorsOnCodeToolChange:=OldChange;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoConvertDelphiProject(const DelphiFilename: string
|
|
): TModalResult;
|
|
var
|
|
OldChange: Boolean;
|
|
Converter: TConvertDelphiProject;
|
|
begin
|
|
InputHistories.LastConvertDelphiProject:=DelphiFilename;
|
|
OldChange:=OpenEditorsOnCodeToolChange;
|
|
OpenEditorsOnCodeToolChange:=true;
|
|
Converter := TConvertDelphiProject.Create(DelphiFilename);
|
|
try
|
|
Result:=Converter.Convert;
|
|
finally
|
|
Converter.Free;
|
|
OpenEditorsOnCodeToolChange:=OldChange;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoConvertDelphiPackage(const DelphiFilename: string
|
|
): TModalResult;
|
|
var
|
|
OldChange: Boolean;
|
|
Converter: TConvertDelphiPackage;
|
|
begin
|
|
InputHistories.LastConvertDelphiPackage:=DelphiFilename;
|
|
OldChange:=OpenEditorsOnCodeToolChange;
|
|
OpenEditorsOnCodeToolChange:=true;
|
|
Converter := TConvertDelphiPackage.Create(DelphiFilename);
|
|
try
|
|
Result:=Converter.Convert;
|
|
finally
|
|
Converter.Free;
|
|
OpenEditorsOnCodeToolChange:=OldChange;
|
|
end;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
procedure TMainIDE.UpdateCustomToolsInMenu;
|
|
|
|
Creates a TMenuItem for each custom external tool.
|
|
-------------------------------------------------------------------------------}
|
|
procedure TMainIDE.UpdateCustomToolsInMenu;
|
|
var
|
|
ToolCount: integer;
|
|
|
|
procedure CreateToolMenuItems;
|
|
var
|
|
Section: TIDEMenuSection;
|
|
begin
|
|
Section:=itmCustomTools;
|
|
// add enough menuitems
|
|
while Section.Count-1<ToolCount do
|
|
RegisterIDEMenuCommand(Section.GetPath,
|
|
'itmToolCustomExt'+IntToStr(Section.Count),'');
|
|
// delete unneeded menuitems
|
|
while Section.Count-1>ToolCount do
|
|
Section[Section.Count-1].Free;
|
|
end;
|
|
|
|
procedure SetToolMenuItems;
|
|
var
|
|
CurMenuItem: TIDEMenuItem;
|
|
i, Index: integer;
|
|
ExtTool: TExternalToolOptions;
|
|
begin
|
|
i:=1;
|
|
Index:=0;
|
|
while (i<itmCustomTools.Count) do begin
|
|
CurMenuItem:=itmCustomTools[i];
|
|
ExtTool:=ExternalTools[Index];
|
|
CurMenuItem.Caption:=ExtTool.Title;
|
|
if CurMenuItem is TIDEMenuCommand then
|
|
TIDEMenuCommand(CurMenuItem).Command:=
|
|
EditorOpts.KeyMap.FindIDECommand(ecExtToolFirst+Index);
|
|
CurMenuItem.OnClick:=@mnuCustomExtToolClick;
|
|
inc(i);
|
|
inc(Index);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
ToolCount:=ExternalTools.Count;
|
|
CreateToolMenuItems;
|
|
SetToolMenuItems;
|
|
end;
|
|
|
|
function TMainIDE.PrepareForCompile: TModalResult;
|
|
begin
|
|
Result:=mrOk;
|
|
if ToolStatus=itDebugger then begin
|
|
Result:=IDEQuestionDialog(lisStopDebugging2,
|
|
lisStopCurrentDebuggingAndRebuildProject,
|
|
mtConfirmation,[mrYes, mrCancel, lisNo],'');
|
|
if Result<>mrYes then exit;
|
|
|
|
Result:=DebugBoss.DoStopProject;
|
|
if Result<>mrOk then exit;
|
|
end;
|
|
|
|
if MainBuildBoss.CompilerOnDiskChanged then
|
|
MainBuildBoss.RescanCompilerDefines(false,false,false,false);
|
|
end;
|
|
|
|
function TMainIDE.OnRunExternalTool(Tool: TIDEExternalToolOptions): TModalResult;
|
|
begin
|
|
SourceEditorManager.ClearErrorLines;
|
|
Result:=ExternalTools.Run(Tool,GlobalMacroList,false);
|
|
DoCheckFilesOnDisk;
|
|
end;
|
|
|
|
function TMainIDE.DoCheckSyntax: TModalResult;
|
|
var
|
|
ActiveUnitInfo:TUnitInfo;
|
|
ActiveSrcEdit:TSourceEditor;
|
|
NewCode: TCodeBuffer;
|
|
NewX, NewY, NewTopLine: integer;
|
|
ErrorMsg: string;
|
|
Handled: Boolean;
|
|
begin
|
|
Result:=mrOk;
|
|
GetCurrentUnit(ActiveSrcEdit,ActiveUnitInfo);
|
|
if (ActiveUnitInfo=nil) or (ActiveUnitInfo.Source=nil)
|
|
or (ActiveSrcEdit=nil) then exit;
|
|
|
|
Handled:=false;
|
|
Result:=DoCallModalHandledHandler(lihtQuickSyntaxCheck,Handled);
|
|
if Handled then exit;
|
|
|
|
SaveSourceEditorChangesToCodeCache(nil);
|
|
CodeToolBoss.VisibleEditorLines:=ActiveSrcEdit.EditorComponent.LinesInWindow;
|
|
if CodeToolBoss.CheckSyntax(ActiveUnitInfo.Source,NewCode,NewX,NewY,
|
|
NewTopLine,ErrorMsg) then
|
|
begin
|
|
DoArrangeSourceEditorAndMessageView(false);
|
|
MessagesView.ClearTillLastSeparator;
|
|
MessagesView.AddSeparator;
|
|
MessagesView.AddMsg(lisMenuQuickSyntaxCheckOk,'',-1);
|
|
end else begin
|
|
DoJumpToCodeToolBossError;
|
|
end;
|
|
if (ErrorMsg='') or (NewTopLine=0) or (NewX=0) or (NewY=0) or (NewCode=nil) then ; // avoid compiler hints about parameters not used
|
|
end;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
procedure TMainIDE.GetCurrentUnit(out ActiveSourceEditor:TSourceEditor;
|
|
out ActiveUnitInfo:TUnitInfo);
|
|
begin
|
|
ActiveSourceEditor := SourceEditorManager.ActiveEditor;
|
|
if ActiveSourceEditor=nil then
|
|
ActiveUnitInfo:=nil
|
|
else
|
|
ActiveUnitInfo := Project1.UnitWithEditorComponent(ActiveSourceEditor);
|
|
end;
|
|
|
|
procedure TMainIDE.GetUnitWithPageIndex(PageIndex, WindowIndex:integer;
|
|
var ActiveSourceEditor:TSourceEditor; var ActiveUnitInfo:TUnitInfo);
|
|
begin
|
|
ActiveSourceEditor := SourceEditorManager.SourceEditorsByPage[WindowIndex, PageIndex];
|
|
if ActiveSourceEditor=nil then
|
|
ActiveUnitInfo:=nil
|
|
else
|
|
ActiveUnitInfo := Project1.UnitWithEditorComponent(ActiveSourceEditor);
|
|
end;
|
|
|
|
procedure TMainIDE.GetDesignerUnit(ADesigner: TDesigner;
|
|
var ActiveSourceEditor: TSourceEditor; var ActiveUnitInfo: TUnitInfo);
|
|
begin
|
|
if ADesigner<>nil then begin
|
|
GetUnitWithForm(ADesigner.Form,ActiveSourceEditor,ActiveUnitInfo);
|
|
end else begin
|
|
ActiveSourceEditor:=nil;
|
|
ActiveUnitInfo:=nil;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.GetProjectFileForProjectEditor(AEditor: TSourceEditorInterface
|
|
): TLazProjectFile;
|
|
begin
|
|
Result := Project1.UnitWithEditorComponent(AEditor);
|
|
end;
|
|
|
|
function TMainIDE.GetDesignerForProjectEditor(AEditor: TSourceEditorInterface;
|
|
LoadForm: boolean): TIDesigner;
|
|
var
|
|
AProjectFile: TLazProjectFile;
|
|
begin
|
|
AProjectFile := Project1.UnitWithEditorComponent(AEditor);
|
|
if AProjectFile <> nil then
|
|
Result:=LazarusIDE.GetDesignerWithProjectFile(
|
|
Project1.UnitWithEditorComponent(AEditor), LoadForm)
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TMainIDE.GetDesignerWithProjectFile(AFile: TLazProjectFile;
|
|
LoadForm: boolean): TIDesigner;
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
AForm: TCustomForm;
|
|
begin
|
|
AnUnitInfo:=AFile as TUnitInfo;
|
|
AForm:=GetDesignerFormOfSource(AnUnitInfo,LoadForm);
|
|
if AForm<>nil then
|
|
Result:=AForm.Designer
|
|
else
|
|
Result:=nil;
|
|
end;
|
|
|
|
procedure TMainIDE.GetObjectInspectorUnit(
|
|
var ActiveSourceEditor: TSourceEditor; var ActiveUnitInfo: TUnitInfo);
|
|
begin
|
|
ActiveSourceEditor:=nil;
|
|
ActiveUnitInfo:=nil;
|
|
if (ObjectInspector1=nil) or (ObjectInspector1.PropertyEditorHook=nil)
|
|
or (ObjectInspector1.PropertyEditorHook.LookupRoot=nil)
|
|
then exit;
|
|
GetUnitWithPersistent(ObjectInspector1.PropertyEditorHook.LookupRoot,
|
|
ActiveSourceEditor,ActiveUnitInfo);
|
|
end;
|
|
|
|
procedure TMainIDE.GetUnitWithForm(AForm: TCustomForm;
|
|
var ActiveSourceEditor: TSourceEditor; var ActiveUnitInfo: TUnitInfo);
|
|
var
|
|
AComponent: TComponent;
|
|
begin
|
|
if AForm<>nil then begin
|
|
if (AForm.Designer=nil) then
|
|
RaiseException('TMainIDE.GetUnitWithForm AForm.Designer');
|
|
AComponent:=TDesigner(AForm.Designer).LookupRoot;
|
|
if AComponent=nil then
|
|
RaiseException('TMainIDE.GetUnitWithForm AComponent=nil');
|
|
GetUnitWithPersistent(AComponent,ActiveSourceEditor,ActiveUnitInfo);
|
|
end else begin
|
|
ActiveSourceEditor:=nil;
|
|
ActiveUnitInfo:=nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.GetUnitWithPersistent(APersistent: TPersistent;
|
|
var ActiveSourceEditor: TSourceEditor; var ActiveUnitInfo: TUnitInfo);
|
|
begin
|
|
if APersistent<>nil then begin
|
|
ActiveUnitInfo:=Project1.FirstUnitWithComponent;
|
|
while ActiveUnitInfo<>nil do begin
|
|
if ActiveUnitInfo.Component=APersistent then begin
|
|
if ActiveUnitInfo.OpenEditorInfoCount > 0 then
|
|
ActiveSourceEditor := TSourceEditor(ActiveUnitInfo.OpenEditorInfo[0].EditorComponent);
|
|
exit;
|
|
end;
|
|
ActiveUnitInfo:=ActiveUnitInfo.NextUnitWithComponent;
|
|
end;
|
|
end;
|
|
ActiveSourceEditor:=nil;
|
|
ActiveUnitInfo:=nil;
|
|
end;
|
|
|
|
function TMainIDE.DoLoadMemoryStreamFromFile(MemStream: TMemoryStream;
|
|
const AFilename:string): TModalResult;
|
|
var FileStream: TFileStream;
|
|
ACaption,AText:string;
|
|
begin
|
|
repeat
|
|
try
|
|
FileStream:=TFileStream.Create(UTF8ToSys(AFilename),fmOpenRead);
|
|
try
|
|
FileStream.Position:=0;
|
|
MemStream.CopyFrom(FileStream,FileStream.Size);
|
|
MemStream.Position:=0;
|
|
finally
|
|
FileStream.Free;
|
|
end;
|
|
Result:=mrOk;
|
|
except
|
|
ACaption:=lisReadError;
|
|
AText:=Format(lisUnableToReadFile2, ['"', AFilename, '"']);
|
|
result := Application.MessageBox(PChar(aText),pChar(aCaption),mb_IconError+mb_AbortRetryIgnore);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
until Result<>mrRetry;
|
|
end;
|
|
|
|
function TMainIDE.DoRenameUnitLowerCase(AnUnitInfo: TUnitInfo;
|
|
AskUser: boolean): TModalresult;
|
|
var
|
|
OldFilename: String;
|
|
OldShortFilename: String;
|
|
NewFilename: String;
|
|
NewShortFilename: String;
|
|
ResourceCode: TCodeBuffer;
|
|
NewUnitName: String;
|
|
begin
|
|
Result:=mrOk;
|
|
OldFilename:=AnUnitInfo.Filename;
|
|
// check if file is unit
|
|
if not FilenameIsPascalUnit(OldFilename) then exit;
|
|
// check if file is already lowercase (or it does not matter in current OS)
|
|
OldShortFilename:=ExtractFilename(OldFilename);
|
|
NewShortFilename:=lowercase(OldShortFilename);
|
|
if CompareFilenames(OldShortFilename,NewShortFilename)=0 then exit;
|
|
// create new filename
|
|
NewFilename:=ExtractFilePath(OldFilename)+NewShortFilename;
|
|
|
|
// rename unit
|
|
if AskUser then begin
|
|
Result:=IDEQuestionDialog(lisFileNotLowercase,
|
|
Format(lisTheUnitIsNotLowercaseTheFreePascalCompiler, ['"',
|
|
OldFilename, '"', #13, #13, #13]),
|
|
mtConfirmation,[mrYes,mrIgnore,lisNo,mrAbort],'');
|
|
if Result<>mrYes then exit;
|
|
end;
|
|
NewUnitName:=AnUnitInfo.Unit_Name;
|
|
if NewUnitName='' then begin
|
|
AnUnitInfo.ReadUnitNameFromSource(false);
|
|
NewUnitName:=AnUnitInfo.CreateUnitName;
|
|
end;
|
|
ResourceCode:=nil;
|
|
Result:=DoRenameUnit(AnUnitInfo,NewFilename,NewUnitName,ResourceCode);
|
|
end;
|
|
|
|
function TMainIDE.DoCheckFilesOnDisk(Instantaneous: boolean): TModalResult;
|
|
var
|
|
AnUnitList: TFPList; // list of TUnitInfo
|
|
APackageList: TFPList; // list of TLazPackage
|
|
i: integer;
|
|
CurUnit: TUnitInfo;
|
|
begin
|
|
Result:=mrOk;
|
|
if FCheckingFilesOnDisk then exit;
|
|
if Project1=nil then exit;
|
|
if Screen.GetCurrentModalForm<>nil then exit;
|
|
|
|
if not Instantaneous then begin
|
|
FCheckFilesOnDiskNeeded:=true;
|
|
exit;
|
|
end;
|
|
FCheckFilesOnDiskNeeded:=false;
|
|
|
|
FCheckingFilesOnDisk:=true;
|
|
AnUnitList:=nil;
|
|
APackageList:=nil;
|
|
try
|
|
InvalidateFileStateCache;
|
|
|
|
if Project1.HasProjectInfoFileChangedOnDisk then begin
|
|
if QuestionDlg(lisProjectChangedOnDisk,
|
|
Format(lisTheProjectInformationFileHasChangedOnDisk, ['"',
|
|
Project1.ProjectInfoFile, '"', #13]), mtConfirmation, [mrYes,
|
|
lisReopenProject, mrIgnore], '')
|
|
=mrYes
|
|
then begin
|
|
DoOpenProjectFile(Project1.ProjectInfoFile,[]);
|
|
end else begin
|
|
Project1.IgnoreProjectInfoFileOnDisk;
|
|
end;
|
|
exit(mrOk);
|
|
end;
|
|
|
|
Project1.GetUnitsChangedOnDisk(AnUnitList);
|
|
PkgBoss.GetPackagesChangedOnDisk(APackageList);
|
|
if (AnUnitList=nil) and (APackageList=nil) then exit;
|
|
Result:=ShowDiskDiffsDialog(AnUnitList,APackageList);
|
|
if Result in [mrYesToAll] then
|
|
Result:=mrOk;
|
|
|
|
// reload units
|
|
if AnUnitList<>nil then begin
|
|
for i:=0 to AnUnitList.Count-1 do begin
|
|
CurUnit:=TUnitInfo(AnUnitList[i]);
|
|
//DebugLn(['TMainIDE.DoCheckFilesOnDisk revert ',CurUnit.Filename,' EditorIndex=',CurUnit.EditorIndex]);
|
|
if Result=mrOk then begin
|
|
if CurUnit.OpenEditorInfoCount > 0 then begin
|
|
// Revert one Editor-View, the others follow
|
|
Result:=DoOpenEditorFile(CurUnit.Filename, CurUnit.OpenEditorInfo[0].PageIndex,
|
|
CurUnit.OpenEditorInfo[0].WindowIndex, [ofRevert]);
|
|
//DebugLn(['TMainIDE.DoCheckFilesOnDisk DoOpenEditorFile=',Result]);
|
|
end else if CurUnit.IsMainUnit then begin
|
|
Result:=DoRevertMainUnit;
|
|
//DebugLn(['TMainIDE.DoCheckFilesOnDisk DoRevertMainUnit=',Result]);
|
|
end else
|
|
Result:=mrIgnore;
|
|
if Result=mrAbort then exit;
|
|
end else begin
|
|
//DebugLn(['TMainIDE.DoCheckFilesOnDisk IgnoreCurrentFileDateOnDisk']);
|
|
CurUnit.IgnoreCurrentFileDateOnDisk;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// reload packages
|
|
Result:=PkgBoss.RevertPackages(APackageList);
|
|
if Result<>mrOk then exit;
|
|
|
|
Result:=mrOk;
|
|
finally
|
|
FCheckingFilesOnDisk:=false;
|
|
AnUnitList.Free;
|
|
APackageList.Free;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoPublishModule(Options: TPublishModuleOptions;
|
|
const SrcDirectory, DestDirectory: string): TModalResult;
|
|
var
|
|
SrcDir, DestDir: string;
|
|
NewProjectFilename: string;
|
|
Tool: TExternalToolOptions;
|
|
CommandAfter, CmdAfterExe, CmdAfterParams: string;
|
|
CurProject: TProject;
|
|
TempCmd: String;
|
|
|
|
procedure ShowErrorForCommandAfter;
|
|
begin
|
|
MessageDlg(lisInvalidCommand,
|
|
Format(lisTheCommandAfterIsNotExecutable, ['"', CmdAfterExe, '"']),
|
|
mtError,[mbCancel],0);
|
|
end;
|
|
|
|
begin
|
|
//DebugLn('TMainIDE.DoPublishModule A');
|
|
Result:=mrCancel;
|
|
|
|
// do not delete project files
|
|
DestDir:=TrimAndExpandDirectory(DestDirectory);
|
|
SrcDir:=TrimAndExpandDirectory(SrcDirectory);
|
|
if (DestDir='') then begin
|
|
MessageDlg('Invalid publishing Directory',
|
|
'Destination directory for publishing is empty.',mtError,
|
|
[mbCancel],0);
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
//DebugLn('TMainIDE.DoPublishModule A SrcDir="',SrcDir,'" DestDir="',DestDir,'"');
|
|
if CompareFilenames(SrcDir,DestDir)=0
|
|
then begin
|
|
MessageDlg(lisInvalidPublishingDirectory,
|
|
Format(lisSourceDirectoryAndDestinationDirectoryAreTheSameMa, ['"',
|
|
SrcDir, '"', #13, '"', DestDir, '"', #13, #13, #13, #13, #13]),
|
|
mtError, [mbCancel], 0);
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
|
|
// check command after
|
|
CommandAfter:=Options.CommandAfter;
|
|
if not GlobalMacroList.SubstituteStr(CommandAfter) then begin
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
SplitCmdLine(CommandAfter,CmdAfterExe,CmdAfterParams);
|
|
if (CmdAfterExe<>'') then begin
|
|
//DebugLn('TMainIDE.DoPublishModule A CmdAfterExe="',CmdAfterExe,'"');
|
|
// first look in the project directory
|
|
TempCmd:=CmdAfterExe;
|
|
if not FilenameIsAbsolute(TempCmd) then
|
|
TempCmd:=TrimFilename(AppendPathDelim(Project1.ProjectDirectory)+TempCmd);
|
|
if FileExistsUTF8(TempCmd) then begin
|
|
CmdAfterExe:=TempCmd;
|
|
end else begin
|
|
TempCmd:=FindDefaultExecutablePath(CmdAfterExe);
|
|
if TempCmd<>'' then
|
|
CmdAfterExe:=TempCmd;
|
|
end;
|
|
if not FileIsExecutableCached(CmdAfterExe) then begin
|
|
MessageDlg(lisCommandAfterInvalid,
|
|
Format(lisTheCommandAfterPublishingIsInvalid, [#13, '"', CmdAfterExe,
|
|
'"']), mtError, [mbCancel], 0);
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
// clear destination directory
|
|
if DirPathExists(DestDir) then begin
|
|
// ask user, if destination can be delete
|
|
if MessageDlg(lisClearDirectory,
|
|
Format(lisInOrderToCreateACleanCopyOfTheProjectPackageAllFil, [#13, #13,
|
|
'"', DestDir, '"']), mtConfirmation,
|
|
[mbYes,mbNo],0)<>mrYes
|
|
then
|
|
exit(mrCancel);
|
|
|
|
if (not DeleteDirectory(ChompPathDelim(DestDir),true)) then begin
|
|
MessageDlg(lisUnableToCleanUpDestinationDirectory,
|
|
Format(lisUnableToCleanUpPleaseCheckPermissions, ['"', DestDir, '"', #13]
|
|
),
|
|
mtError,[mbOk],0);
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
// copy the directory
|
|
if not CopyDirectoryWithMethods(SrcDir,DestDir,
|
|
@OnCopyFile,@OnCopyError,Options) then
|
|
begin
|
|
debugln('TMainIDE.DoPublishModule CopyDirectoryWithMethods failed');
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
|
|
// write a filtered .lpi file
|
|
if Options is TPublishProjectOptions then begin
|
|
CurProject:=TProject(TPublishProjectOptions(Options).Owner);
|
|
NewProjectFilename:=DestDir+ExtractFilename(CurProject.ProjectInfoFile);
|
|
DeleteFileUTF8(NewProjectFilename);
|
|
Result:=CurProject.WriteProject(CurProject.PublishOptions.WriteFlags
|
|
+[pwfSkipDebuggerSettings,pwfSkipJumpPoints,pwfDoNotSaveSessionInfo,
|
|
pwfIgnoreModified],
|
|
NewProjectFilename);
|
|
if Result<>mrOk then begin
|
|
debugln('TMainIDE.DoPublishModule CurProject.WriteProject failed');
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
// execute 'CommandAfter'
|
|
if (CmdAfterExe<>'') then begin
|
|
if FileIsExecutableCached(CmdAfterExe) then begin
|
|
Tool:=TExternalToolOptions.Create;
|
|
Tool.Filename:=CmdAfterExe;
|
|
Tool.Title:=lisCommandAfterPublishingModule;
|
|
Tool.WorkingDirectory:=DestDir;
|
|
Tool.CmdLineParams:=CmdAfterParams;
|
|
Result:=ExternalTools.Run(Tool,GlobalMacroList,false);
|
|
if Result<>mrOk then exit;
|
|
end else begin
|
|
ShowErrorForCommandAfter;
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.AbortBuild;
|
|
begin
|
|
if TheOutputFilter<>nil then
|
|
TheOutputFilter.StopExecute:=true;
|
|
end;
|
|
|
|
procedure TMainIDE.UpdateCaption;
|
|
var
|
|
NewCaption: String;
|
|
|
|
procedure AddToCaption(const CaptAddition: string);
|
|
begin
|
|
if EnvironmentOptions.IDETitleStartsWithProject then
|
|
NewCaption := CaptAddition + ' - ' + NewCaption
|
|
else
|
|
NewCaption := NewCaption + ' - ' + CaptAddition;
|
|
end;
|
|
|
|
var
|
|
NewTitle, ProjectName, DirName: String;
|
|
begin
|
|
if MainIDEBar = nil then Exit;
|
|
if ToolStatus = itExiting then Exit;
|
|
NewCaption := Format(lisLazarusEditorV, [GetLazarusVersionString]);
|
|
NewTitle := NewCaption;
|
|
if MainBarSubTitle <> '' then
|
|
AddToCaption(MainBarSubTitle)
|
|
else
|
|
begin
|
|
if Project1 <> nil then
|
|
begin
|
|
ProjectName := Project1.GetTitleOrName;
|
|
if ProjectName <> '' then
|
|
begin
|
|
if EnvironmentOptions.IDEProjectDirectoryInIdeTitle then
|
|
begin
|
|
DirName := ExtractFileDir(Project1.ProjectInfoFile);
|
|
if DirName <> '' then
|
|
ProjectName := ProjectName + ' ('+DirName+')';
|
|
end;
|
|
AddToCaption(ProjectName);
|
|
end
|
|
else
|
|
AddToCaption(lisnewProject);
|
|
NewTitle := NewCaption;
|
|
end;
|
|
end;
|
|
case ToolStatus of
|
|
itBuilder: NewCaption := Format(liscompiling, [NewCaption]);
|
|
itDebugger:
|
|
begin
|
|
if DebugBoss.Commands - [dcRun, dcStop, dcEnvironment] <> [] then
|
|
NewCaption := Format(lisDebugging, [NewCaption])
|
|
else
|
|
NewCaption := Format(lisRunning, [NewCaption]);
|
|
end;
|
|
end;
|
|
MainIDEBar.Caption := NewCaption;
|
|
Application.Title := NewTitle;
|
|
end;
|
|
|
|
procedure TMainIDE.HideIDE;
|
|
var
|
|
i: Integer;
|
|
AForm: TCustomForm;
|
|
begin
|
|
// hide hints
|
|
Application.HideHint;
|
|
SourceEditorManager.HideHint;
|
|
|
|
// hide designer forms
|
|
HideUnmodifiedDesigners;
|
|
|
|
// collect all windows except the main bar
|
|
for i:=0 to Screen.CustomFormCount-1 do begin
|
|
AForm:=Screen.CustomForms[i];
|
|
if (AForm.Parent=nil) // ignore nested forms
|
|
and (AForm<>MainIDEBar) // ignore the main bar
|
|
and (AForm.Designer=nil) // ignore designer forms
|
|
and (not (csDesigning in AForm.ComponentState))
|
|
and (AForm.IsVisible) // ignore hidden forms
|
|
and (not (fsModal in AForm.FormState)) // ignore modal forms
|
|
and (HiddenWindowsOnRun.IndexOf(AForm)<0) // ignore already collected forms
|
|
then
|
|
HiddenWindowsOnRun.Add(AForm);
|
|
end;
|
|
|
|
// hide all collected windows
|
|
for i:=0 to HiddenWindowsOnRun.Count-1 do begin
|
|
AForm:=TCustomForm(HiddenWindowsOnRun[i]);
|
|
AForm.Hide;
|
|
end;
|
|
|
|
// minimize IDE
|
|
MainIDEBar.HideIDE;
|
|
end;
|
|
|
|
procedure TMainIDE.HideUnmodifiedDesigners;
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
NextUnitInfo: TUnitInfo;
|
|
begin
|
|
AnUnitInfo:=Project1.FirstUnitWithComponent;
|
|
while AnUnitInfo<>nil do begin
|
|
NextUnitInfo:=AnUnitInfo.NextUnitWithComponent;
|
|
if not AnUnitInfo.NeedsSaveToDisk then
|
|
CloseUnitComponent(AnUnitInfo,[]);
|
|
AnUnitInfo:=NextUnitInfo;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.UnhideIDE;
|
|
var
|
|
AForm: TCustomForm;
|
|
begin
|
|
// unminimize IDE
|
|
MainIDEBar.UnhideIDE;
|
|
|
|
// show other windows
|
|
while HiddenWindowsOnRun.Count>0 do begin
|
|
AForm:=TCustomForm(HiddenWindowsOnRun[0]);
|
|
if (csDesigning in ComponentState) then
|
|
ShowDesignerForm(AForm)
|
|
else
|
|
AForm.Show;
|
|
HiddenWindowsOnRun.Delete(0);
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.DoBringToFrontFormOrUnit;
|
|
begin
|
|
if FDisplayState = dsSource then begin
|
|
DoShowDesignerFormOfCurrentSrc;
|
|
end else begin
|
|
DoShowSourceOfActiveDesignerForm;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.DoBringToFrontFormOrInspector(ForceInspector: boolean);
|
|
|
|
procedure ShowInspector;
|
|
begin
|
|
if ObjectInspector1=nil then exit;
|
|
IDEWindowCreators.ShowForm(ObjectInspector1,true);
|
|
if ObjectInspector1.IsVisible then
|
|
begin
|
|
ObjectInspector1.FocusGrid;
|
|
if FDisplayState <> high(TDisplayState) then
|
|
FDisplayState:= Succ(FDisplayState);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if ForceInspector then begin
|
|
ShowInspector;
|
|
exit;
|
|
end;
|
|
case FDisplayState of
|
|
|
|
dsInspector:
|
|
DoShowDesignerFormOfCurrentSrc;
|
|
|
|
dsInspector2:
|
|
DoShowSourceOfActiveDesignerForm;
|
|
|
|
else
|
|
ShowInspector;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.DoShowDesignerFormOfCurrentSrc;
|
|
var
|
|
ActiveSourceEditor: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
AForm: TCustomForm;
|
|
begin
|
|
GetCurrentUnit(ActiveSourceEditor,ActiveUnitInfo);
|
|
if (ActiveUnitInfo = nil) then exit;
|
|
// load the form, if not already done
|
|
AForm:=GetDesignerFormOfSource(ActiveUnitInfo,true);
|
|
if AForm=nil then exit;
|
|
FDisplayState:= dsForm;
|
|
FLastFormActivated:=AForm;
|
|
ShowDesignerForm(AForm);
|
|
if TheControlSelection.SelectionForm<>AForm then begin
|
|
// select the new form (object inspector, formeditor, control selection)
|
|
TheControlSelection.AssignPersistent(ActiveUnitInfo.Component);
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.DoShowSourceOfActiveDesignerForm;
|
|
var
|
|
ActiveUnitInfo: TUnitInfo;
|
|
begin
|
|
if SourceEditorManager.SourceEditorCount = 0 then exit;
|
|
if FLastFormActivated <> nil then begin
|
|
ActiveUnitInfo:= Project1.UnitWithComponent(
|
|
TDesigner(FLastFormActivated.Designer).LookupRoot);
|
|
if (ActiveUnitInfo <> nil) and (ActiveUnitInfo.OpenEditorInfoCount > 0) then
|
|
begin
|
|
SourceEditorManager.ActiveEditor := TSourceEditor(ActiveUnitInfo.OpenEditorInfo[0].EditorComponent);
|
|
end;
|
|
end;
|
|
SourceEditorManager.ShowActiveWindowOnTop(False);
|
|
FDisplayState:= dsSource;
|
|
end;
|
|
|
|
procedure TMainIDE.OnMacroSubstitution(TheMacro: TTransferMacro;
|
|
const MacroName: string; var s:string;
|
|
const Data: PtrInt; var Handled, Abort: boolean; Depth: integer);
|
|
var MacroLName:string;
|
|
begin
|
|
if TheMacro=nil then begin
|
|
DebugLn('WARNING: Macro not defined: "'+MacroName+'".');
|
|
s:='';
|
|
//MessageDlg('Unknown Macro','Macro not defined: "'+s+'".',mtError,[mbAbort],0);
|
|
Handled:=true;
|
|
exit;
|
|
end;
|
|
MacroLName:=lowercase(MacroName);
|
|
Handled:=true;
|
|
if MacroLName='save' then begin
|
|
if (SourceEditorManager<>nil) and (SourceEditorManager.SourceEditorCount > 0) then
|
|
Abort:=(DoSaveEditorFile(SourceEditorManager.ActiveEditor,
|
|
[sfCheckAmbiguousFiles]) <> mrOk);
|
|
s:='';
|
|
end else if MacroLName='saveall' then begin
|
|
Abort:=(DoSaveAll([sfCheckAmbiguousFiles])<>mrOk);
|
|
s:='';
|
|
end else
|
|
Handled:=false;
|
|
end;
|
|
|
|
procedure TMainIDE.GetIDEFileState(Sender: TObject; const AFilename: string;
|
|
NeededFlags: TIDEFileStateFlags; out ResultFlags: TIDEFileStateFlags);
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
ResultFlags:=[];
|
|
AnUnitInfo:=Project1.UnitInfoWithFilename(AFilename);
|
|
if AnUnitInfo<>nil then begin
|
|
// readonly
|
|
if (ifsReadOnly in NeededFlags) and AnUnitInfo.ReadOnly then
|
|
Include(ResultFlags,ifsReadOnly);
|
|
// part of project
|
|
if (ifsPartOfProject in NeededFlags) and AnUnitInfo.IsPartOfProject then
|
|
Include(ResultFlags,ifsPartOfProject);
|
|
// open in editor
|
|
if (ifsOpenInEditor in NeededFlags) and (AnUnitInfo.OpenEditorInfoCount > 0) then
|
|
Include(ResultFlags,ifsOpenInEditor);
|
|
end else if FileExistsUTF8(AFilename) then begin
|
|
// readonly
|
|
if (ifsReadOnly in NeededFlags) and (not FileIsWritable(AFilename)) then
|
|
Include(ResultFlags,ifsReadOnly);
|
|
end;
|
|
end;
|
|
|
|
function GetFPCMessage(ALine: TLazMessageLine; var FileName: String; var CaretPos: TPoint; var ErrType: TFPCErrorType): Boolean;
|
|
begin
|
|
Result := Assigned(ALine.Parts);
|
|
if Result and (ALine.Filename = '') then
|
|
ALine.UpdateSourcePosition;
|
|
FileName:=ALine.Filename;
|
|
CaretPos.x:=ALine.Column;
|
|
CaretPos.y:=ALine.LineNumber;
|
|
if not Result then
|
|
Exit;
|
|
ErrType:=FPCErrorTypeNameToType(ALine.Parts.Values['Type']);
|
|
end;
|
|
|
|
function TMainIDE.DoJumpToCompilerMessage(Index:integer;
|
|
FocusEditor: boolean): boolean;
|
|
var
|
|
MaxMessages: integer;
|
|
Filename, SearchedFilename: string;
|
|
LogCaretXY: TPoint;
|
|
TopLine: integer;
|
|
MsgType: TFPCErrorType;
|
|
SrcEdit: TSourceEditor;
|
|
OpenFlags: TOpenFlags;
|
|
CurDir: string;
|
|
NewFilename: String;
|
|
AnUnitInfo: TUnitInfo;
|
|
AnEditorInfo: TUnitEditorInfo;
|
|
MsgLine: TLazMessageLine;
|
|
begin
|
|
Result:=false;
|
|
|
|
MaxMessages:=MessagesView.VisibleItemCount;
|
|
if Index>=MaxMessages then exit;
|
|
if (Index<0) then begin
|
|
// search relevant message (first error, first fatal)
|
|
Index:=0;
|
|
while (Index<MaxMessages) do begin
|
|
// ParseFPCMessage doesn't support multilingual messages, by GetFPCMessage
|
|
MsgLine:=MessagesView.VisibleItems[Index];
|
|
if GetFPCMessage(MsgLine,Filename,LogCaretXY,MsgType) then
|
|
begin
|
|
if MsgType in [etError,etFatal,etPanic] then break;
|
|
end;
|
|
inc(Index);
|
|
end;
|
|
if Index>=MaxMessages then exit;
|
|
end;
|
|
MessagesView.SelectedMessageIndex:=Index;
|
|
|
|
// first try the plugins
|
|
if MessagesView.ExecuteMsgLinePlugin(imqfoJump) then exit;
|
|
|
|
// default: jump to source position
|
|
MsgLine:=MessagesView.VisibleItems[Index];
|
|
if GetFPCMessage(MsgLine,Filename,LogCaretXY,MsgType) then begin
|
|
//debugln(['TMainIDE.DoJumpToCompilerMessage Index=',Index,' MsgFile=',MsgLine.Filename,' MsgY=',MsgLine.LineNumber,' File=',Filename,' XY=',dbgs(LogCaretXY),' ',MsgLine.Parts.Text]);
|
|
CurDir:=MsgLine.Directory;
|
|
if (not FilenameIsAbsolute(Filename)) and (CurDir<>'') then begin
|
|
// the directory was just hidden, re-append it
|
|
NewFilename:=AppendPathDelim(CurDir)+Filename;
|
|
if FileExistsUTF8(NewFilename) then
|
|
Filename:=NewFilename;
|
|
end;
|
|
|
|
OpenFlags:=[ofOnlyIfExists,ofRegularFile];
|
|
if MainBuildBoss.IsTestUnitFilename(Filename) then begin
|
|
SearchedFilename := ExtractFileName(Filename);
|
|
Include(OpenFlags,ofVirtualFile);
|
|
end else begin
|
|
SearchedFilename := FindUnitFile(Filename);
|
|
if not FilenameIsAbsolute(SearchedFilename) then
|
|
Include(OpenFlags,ofVirtualFile);
|
|
end;
|
|
|
|
if SearchedFilename<>'' then begin
|
|
// open the file in the source editor
|
|
AnUnitInfo := Project1.UnitInfoWithFilename(SearchedFilename);
|
|
AnEditorInfo := nil;
|
|
if AnUnitInfo <> nil then
|
|
AnEditorInfo := GetAvailableUnitEditorInfo(AnUnitInfo, LogCaretXY);
|
|
if AnEditorInfo <> nil then begin
|
|
SourceEditorManager.ActiveEditor := TSourceEditor(AnEditorInfo.EditorComponent);
|
|
Result := True;
|
|
end
|
|
else
|
|
Result:=(DoOpenEditorFile(SearchedFilename,-1,-1,OpenFlags)=mrOk);
|
|
if Result then begin
|
|
// set caret position
|
|
SourceEditorManager.AddJumpPointClicked(Self);
|
|
SrcEdit:=SourceEditorManager.ActiveEditor;
|
|
if LogCaretXY.Y>SrcEdit.EditorComponent.Lines.Count then
|
|
LogCaretXY.Y:=SrcEdit.EditorComponent.Lines.Count;
|
|
if LogCaretXY.X<1 then
|
|
LogCaretXY.X:=1;
|
|
TopLine:=LogCaretXY.Y-(SrcEdit.EditorComponent.LinesInWindow div 2);
|
|
if TopLine<1 then TopLine:=1;
|
|
if FocusEditor then begin
|
|
IDEWindowCreators.ShowForm(MessagesView,true);
|
|
SourceEditorManager.ShowActiveWindowOnTop(True);
|
|
end;
|
|
SrcEdit.EditorComponent.LogicalCaretXY:=LogCaretXY;
|
|
SrcEdit.EditorComponent.TopLine:=TopLine;
|
|
SrcEdit.CenterCursorHoriz(hcmSoftKeepEOL);
|
|
SrcEdit.ErrorLine:=LogCaretXY.Y;
|
|
end;
|
|
end else begin
|
|
if FilenameIsAbsolute(Filename) then begin
|
|
MessageDlg(Format(lisUnableToFindFile, ['"', Filename, '"']),
|
|
mtInformation,[mbOk],0)
|
|
end else if Filename<>'' then begin
|
|
MessageDlg(Format(
|
|
lisUnableToFindFileCheckSearchPathInProjectCompilerOption, ['"',
|
|
Filename, '"', #13, #13]),
|
|
mtInformation,[mbOk],0);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.DoJumpToNextError(DirectionDown: boolean);
|
|
var
|
|
Index: integer;
|
|
MaxMessages: integer;
|
|
Filename: string;
|
|
LogCaretXY: TPoint;
|
|
MsgType: TFPCErrorType;
|
|
OldIndex: integer;
|
|
RoundCount: Integer;
|
|
begin
|
|
// search relevant message (next error, fatal or panic)
|
|
MaxMessages:=MessagesView.VisibleItemCount;
|
|
OldIndex:=MessagesView.SelectedMessageIndex;
|
|
Index:=OldIndex;
|
|
RoundCount:=0;
|
|
while (Index>=0) and (Index<MaxMessages) do begin
|
|
// goto to next message
|
|
if DirectionDown then begin
|
|
inc(Index);
|
|
if Index>=MaxMessages then begin
|
|
inc(RoundCount);
|
|
Index:=0;
|
|
end;
|
|
end else begin
|
|
dec(Index);
|
|
if Index<0 then begin
|
|
inc(RoundCount);
|
|
Index:=MaxMessages-1;
|
|
end;
|
|
end;
|
|
if(Index=OldIndex) or (RoundCount>1) then exit;
|
|
|
|
// check if it is an error
|
|
if GetFPCMessage(MessagesView.VisibleItems[Index],Filename,LogCaretXY,MsgType) then
|
|
begin
|
|
if MsgType in [etError,etFatal,etPanic] then break;
|
|
end;
|
|
end;
|
|
MessagesView.SelectedMessageIndex:=Index;
|
|
DoJumpToCompilerMessage(Index,true);
|
|
end;
|
|
|
|
function TMainIDE.DoJumpToSearchResult(FocusEditor: boolean): boolean;
|
|
var
|
|
AFileName: string;
|
|
SearchedFilename: string;
|
|
LogCaretXY: TPoint;
|
|
OpenFlags: TOpenFlags;
|
|
SrcEdit: TSourceEditor;
|
|
AnUnitInfo: TUnitInfo;
|
|
AnEditorInfo: TUnitEditorInfo;
|
|
begin
|
|
Result:=false;
|
|
if pos('(',SearchResultsView.GetSelectedText) > 0 then
|
|
begin
|
|
AFileName:= SearchResultsView.GetSourceFileName;
|
|
if AFilename='' then exit;
|
|
LogCaretXY:= SearchResultsView.GetSourcePositon;
|
|
OpenFlags:=[ofOnlyIfExists,ofRegularFile];
|
|
if MainBuildBoss.IsTestUnitFilename(AFilename) then begin
|
|
SearchedFilename := ExtractFileName(AFilename);
|
|
Include(OpenFlags,ofVirtualFile);
|
|
end else begin
|
|
SearchedFilename := FindUnitFile(AFilename);
|
|
end;
|
|
if SearchedFilename<>'' then begin
|
|
// open the file in the source editor
|
|
AnUnitInfo := Project1.UnitInfoWithFilename(SearchedFilename);
|
|
AnEditorInfo := nil;
|
|
if AnUnitInfo <> nil then
|
|
AnEditorInfo := GetAvailableUnitEditorInfo(AnUnitInfo, LogCaretXY);
|
|
if AnEditorInfo <> nil then begin
|
|
SourceEditorManager.ActiveEditor := TSourceEditor(AnEditorInfo.EditorComponent);
|
|
Result := True;
|
|
end else
|
|
Result:=(DoOpenEditorFile(SearchedFilename,-1,-1,OpenFlags)=mrOk);
|
|
if Result then begin
|
|
// set caret position
|
|
SourceEditorManager.AddJumpPointClicked(Self);
|
|
SrcEdit:=SourceEditorManager.ActiveEditor;
|
|
if LogCaretXY.Y>SrcEdit.EditorComponent.Lines.Count then
|
|
LogCaretXY.Y:=SrcEdit.EditorComponent.Lines.Count;
|
|
if FocusEditor then begin
|
|
IDEWindowCreators.ShowForm(SearchResultsView,true);
|
|
SourceEditorManager.ShowActiveWindowOnTop(True);
|
|
end;
|
|
try
|
|
SrcEdit.BeginUpdate;
|
|
SrcEdit.EditorComponent.LogicalCaretXY:=LogCaretXY;
|
|
if not SrcEdit.IsLocked then begin
|
|
SrcEdit.CenterCursor(True);
|
|
SrcEdit.CenterCursorHoriz(hcmSoftKeepEOL);
|
|
end;
|
|
finally
|
|
SrcEdit.EndUpdate;
|
|
end;
|
|
SrcEdit.ErrorLine:=LogCaretXY.Y;
|
|
end;
|
|
end else if AFilename<>'' then begin
|
|
if FilenameIsAbsolute(AFilename) then begin
|
|
MessageDlg(Format(lisUnableToFindFile, ['"', AFilename, '"']),
|
|
mtInformation,[mbOk],0)
|
|
end else if AFileName<>'' then begin
|
|
MessageDlg(Format(
|
|
lisUnableToFindFileCheckSearchPathInProjectCompilerOption, ['"',
|
|
AFilename, '"', #13, #13]),
|
|
mtInformation,[mbOk],0);
|
|
end;
|
|
end;
|
|
end;//if
|
|
end;
|
|
|
|
procedure TMainIDE.DoShowMessagesView(BringToFront: boolean);
|
|
begin
|
|
//debugln('TMainIDE.DoShowMessagesView');
|
|
if EnvironmentOptions.HideMessagesIcons then
|
|
MessagesView.MessageTreeView.Images := nil
|
|
else
|
|
MessagesView.MessageTreeView.Images := IDEImages.Images_12;
|
|
|
|
// don't move the messagesview, if it was already visible.
|
|
IDEWindowCreators.ShowForm(MessagesView,BringToFront);
|
|
if BringToFront then
|
|
// the sourcenotebook is more interesting than the messages
|
|
SourceEditorManager.ShowActiveWindowOnTop(False);
|
|
end;
|
|
|
|
procedure TMainIDE.DoShowSearchResultsView(Show, BringToFront: boolean);
|
|
begin
|
|
//set the event here for the selectionchanged event
|
|
if not assigned(SearchresultsView.OnSelectionChanged) then
|
|
SearchresultsView.OnSelectionChanged := @SearchresultsViewSelectionChanged;
|
|
|
|
if Show and (not SearchResultsView.IsVisible) then
|
|
begin
|
|
IDEWindowCreators.ShowForm(SearchResultsView,BringToFront);
|
|
// the sourcenotebook is more interesting than the search results
|
|
SourceEditorManager.ShowActiveWindowOnTop(False);
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.DoArrangeSourceEditorAndMessageView(PutOnTop: boolean);
|
|
var
|
|
SrcNoteBook: TSourceNotebook;
|
|
Layout: TSimpleWindowLayout;
|
|
begin
|
|
DoShowMessagesView(PutOnTop);
|
|
if SourceEditorManager.SourceWindowCount = 0 then exit;
|
|
SrcNoteBook := SourceEditorManager.SourceWindows[0];
|
|
|
|
Layout:=IDEWindowCreators.SimpleLayoutStorage.ItemByFormID(SrcNoteBook.Name);
|
|
if (Layout<>nil) and (Layout.WindowPlacement=iwpDefault)
|
|
and ((SrcNoteBook.Top + SrcNoteBook.Height) > MessagesView.Top)
|
|
and (MessagesView.Parent = nil) then
|
|
SrcNoteBook.Height := Max(50,Min(SrcNoteBook.Height,
|
|
MessagesView.Top-SrcNoteBook.Top));
|
|
if PutOnTop then
|
|
begin
|
|
IDEWindowCreators.ShowForm(MessagesView,true);
|
|
SourceEditorManager.ShowActiveWindowOnTop(False);
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.GetTestBuildDirectory: string;
|
|
begin
|
|
Result:=MainBuildBoss.GetTestBuildDirectory;
|
|
end;
|
|
|
|
function TMainIDE.FindUnitFile(const AFilename: string; TheOwner: TObject;
|
|
Flags: TFindUnitFileFlags): string;
|
|
|
|
function FindInBaseIDE: string;
|
|
var
|
|
AnUnitName: String;
|
|
BaseDir: String;
|
|
UnitInFilename: String;
|
|
begin
|
|
AnUnitName:=ExtractFileNameOnly(AFilename);
|
|
BaseDir:=EnvironmentOptions.LazarusDirectory+PathDelim+'ide';
|
|
UnitInFilename:='';
|
|
Result:=CodeToolBoss.DirectoryCachePool.FindUnitSourceInCompletePath(
|
|
BaseDir,AnUnitName,UnitInFilename,true);
|
|
end;
|
|
|
|
function FindInProject(AProject: TProject): string;
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
AnUnitName: String;
|
|
BaseDir: String;
|
|
UnitInFilename: String;
|
|
begin
|
|
// search in virtual (unsaved) files
|
|
AnUnitInfo:=AProject.UnitInfoWithFilename(AFilename,
|
|
[pfsfOnlyProjectFiles,pfsfOnlyVirtualFiles]);
|
|
if AnUnitInfo<>nil then begin
|
|
Result:=AnUnitInfo.Filename;
|
|
exit;
|
|
end;
|
|
|
|
// search in search path of project
|
|
AnUnitName:=ExtractFileNameOnly(AFilename);
|
|
BaseDir:=AProject.ProjectDirectory;
|
|
UnitInFilename:='';
|
|
Result:=CodeToolBoss.DirectoryCachePool.FindUnitSourceInCompletePath(
|
|
BaseDir,AnUnitName,UnitInFilename,true);
|
|
end;
|
|
|
|
function FindInPackage(APackage: TLazPackage): string;
|
|
var
|
|
BaseDir: String;
|
|
AnUnitName: String;
|
|
UnitInFilename: String;
|
|
begin
|
|
Result:='';
|
|
BaseDir:=APackage.Directory;
|
|
if not FilenameIsAbsolute(BaseDir) then exit;
|
|
// search in search path of package
|
|
AnUnitName:=ExtractFileNameOnly(AFilename);
|
|
UnitInFilename:='';
|
|
Result:=CodeToolBoss.DirectoryCachePool.FindUnitSourceInCompletePath(
|
|
BaseDir,AnUnitName,UnitInFilename,true);
|
|
end;
|
|
|
|
var
|
|
AProject: TProject;
|
|
i: Integer;
|
|
begin
|
|
if FilenameIsAbsolute(AFilename) then begin
|
|
Result:=AFilename;
|
|
exit;
|
|
end;
|
|
Result:='';
|
|
|
|
// project
|
|
AProject:=nil;
|
|
if TheOwner=nil then begin
|
|
AProject:=Project1;
|
|
end else if (TheOwner is TProject) then
|
|
AProject:=TProject(TheOwner);
|
|
|
|
if AProject<>nil then
|
|
begin
|
|
Result:=FindInProject(AProject);
|
|
if Result<>'' then exit;
|
|
end;
|
|
|
|
// package
|
|
if TheOwner is TLazPackage then begin
|
|
Result:=FindInPackage(TLazPackage(TheOwner));
|
|
if Result<>'' then exit;
|
|
end;
|
|
|
|
if TheOwner=Self then begin
|
|
// search in base IDE
|
|
Result:=FindInBaseIDE;
|
|
if Result<>'' then exit;
|
|
|
|
// search in installed packages
|
|
for i:=0 to PackageGraph.Count-1 do
|
|
if (PackageGraph[i].Installed<>pitNope)
|
|
and ((not (fuffIgnoreUninstallPackages in Flags))
|
|
or (PackageGraph[i].AutoInstall<>pitNope))
|
|
then begin
|
|
Result:=FindInPackage(PackageGraph[i]);
|
|
if Result<>'' then exit;
|
|
end;
|
|
// search in auto install packages
|
|
for i:=0 to PackageGraph.Count-1 do
|
|
if (PackageGraph[i].Installed=pitNope)
|
|
and (PackageGraph[i].AutoInstall<>pitNope) then begin
|
|
Result:=FindInPackage(PackageGraph[i]);
|
|
if Result<>'' then exit;
|
|
end;
|
|
// then search in all other open packages
|
|
for i:=0 to PackageGraph.Count-1 do
|
|
if (PackageGraph[i].Installed=pitNope)
|
|
and (PackageGraph[i].AutoInstall=pitNope) then begin
|
|
Result:=FindInPackage(PackageGraph[i]);
|
|
if Result<>'' then exit;
|
|
end;
|
|
end;
|
|
Result:='';
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
function TMainIDE.FindSourceFile(const AFilename, BaseDirectory: string;
|
|
Flags: TFindSourceFlags): string;
|
|
|
|
AFilename can be an absolute or relative filename, of a source file or a
|
|
compiled unit (.ppu).
|
|
Find the source filename (pascal source or include file) and returns
|
|
the absolute path.
|
|
With fsfMapTempToVirtualFiles files in the temp directory are stripped off
|
|
the temporary files resulting in the virtual file name of the CodeTools.
|
|
|
|
First it searches in the current projects src path, then its unit path, then
|
|
its include path. Then all used package source directories are searched.
|
|
Finally the fpc sources are searched.
|
|
------------------------------------------------------------------------------}
|
|
function TMainIDE.FindSourceFile(const AFilename, BaseDirectory: string;
|
|
Flags: TFindSourceFlags): string;
|
|
var
|
|
CompiledSrcExt: String;
|
|
BaseDir: String;
|
|
AlreadySearchedPaths: string;
|
|
StartUnitPath: String;
|
|
|
|
procedure MarkPathAsSearched(const AddSearchPath: string);
|
|
begin
|
|
AlreadySearchedPaths:=MergeSearchPaths(AlreadySearchedPaths,AddSearchPath);
|
|
end;
|
|
|
|
function SearchIndirectIncludeFile: string;
|
|
var
|
|
UnitPath: String;
|
|
CurDir: String;
|
|
AlreadySearchedUnitDirs: String;
|
|
CompiledUnitPath: String;
|
|
AllSrcPaths: String;
|
|
CurSrcPath: String;
|
|
CurIncPath: String;
|
|
PathPos: Integer;
|
|
AllIncPaths: String;
|
|
SearchPath: String;
|
|
SearchFile: String;
|
|
begin
|
|
if CompiledSrcExt='' then exit;
|
|
// get unit path for compiled units
|
|
UnitPath:=BaseDir+';'+StartUnitPath;
|
|
UnitPath:=TrimSearchPath(UnitPath,BaseDir);
|
|
|
|
// Extract all directories with compiled units
|
|
CompiledUnitPath:='';
|
|
AlreadySearchedUnitDirs:='';
|
|
PathPos:=1;
|
|
while PathPos<=length(UnitPath) do begin
|
|
CurDir:=GetNextDirectoryInSearchPath(UnitPath,PathPos);
|
|
// check if directory is already tested
|
|
if SearchDirectoryInSearchPath(AlreadySearchedUnitDirs,CurDir,1)>0 then
|
|
continue;
|
|
AlreadySearchedUnitDirs:=MergeSearchPaths(AlreadySearchedUnitDirs,CurDir);
|
|
// check if directory contains a compiled unit
|
|
if FindFirstFileWithExt(CurDir,CompiledSrcExt)<>'' then
|
|
CompiledUnitPath:=CompiledUnitPath+';'+CurDir;
|
|
end;
|
|
{$IFDEF VerboseFindSourceFile}
|
|
debugln(['TMainIDE.SearchIndirectIncludeFile CompiledUnitPath="',CompiledUnitPath,'"']);
|
|
{$ENDIF}
|
|
|
|
// collect all src paths for the compiled units
|
|
AllSrcPaths:=CompiledUnitPath;
|
|
PathPos:=1;
|
|
while PathPos<=length(CompiledUnitPath) do begin
|
|
CurDir:=GetNextDirectoryInSearchPath(CompiledUnitPath,PathPos);
|
|
CurSrcPath:=CodeToolBoss.GetCompiledSrcPathForDirectory(CurDir);
|
|
CurSrcPath:=TrimSearchPath(CurSrcPath,CurDir);
|
|
AllSrcPaths:=MergeSearchPaths(AllSrcPaths,CurSrcPath);
|
|
end;
|
|
{$IFDEF VerboseFindSourceFile}
|
|
debugln(['TMainIDE.SearchIndirectIncludeFile AllSrcPaths="',AllSrcPaths,'"']);
|
|
{$ENDIF}
|
|
|
|
// add fpc src directories
|
|
// ToDo
|
|
|
|
// collect all include paths
|
|
AllIncPaths:=AllSrcPaths;
|
|
PathPos:=1;
|
|
while PathPos<=length(AllSrcPaths) do begin
|
|
CurDir:=GetNextDirectoryInSearchPath(AllSrcPaths,PathPos);
|
|
CurIncPath:=CodeToolBoss.GetIncludePathForDirectory(CurDir);
|
|
CurIncPath:=TrimSearchPath(CurIncPath,CurDir);
|
|
AllIncPaths:=MergeSearchPaths(AllIncPaths,CurIncPath);
|
|
end;
|
|
{$IFDEF VerboseFindSourceFile}
|
|
debugln(['TMainIDE.SearchIndirectIncludeFile AllIncPaths="',AllIncPaths,'"']);
|
|
{$ENDIF}
|
|
|
|
SearchFile:=AFilename;
|
|
SearchPath:=AllIncPaths;
|
|
Result:=FileUtil.SearchFileInPath(SearchFile,BaseDir,SearchPath,';',[]);
|
|
{$IFDEF VerboseFindSourceFile}
|
|
debugln(['TMainIDE.SearchIndirectIncludeFile Result="',Result,'"']);
|
|
{$ENDIF}
|
|
MarkPathAsSearched(SearchPath);
|
|
end;
|
|
|
|
function SearchInPath(const TheSearchPath, SearchFile: string;
|
|
var Filename: string): boolean;
|
|
var
|
|
SearchPath: String;
|
|
begin
|
|
Filename:='';
|
|
SearchPath:=RemoveSearchPaths(TheSearchPath,AlreadySearchedPaths);
|
|
if SearchPath<>'' then begin
|
|
Filename:=FileUtil.SearchFileInPath(SearchFile,BaseDir,SearchPath,';',[]);
|
|
{$IFDEF VerboseFindSourceFile}
|
|
debugln(['TMainIDE.FindSourceFile trying "',SearchPath,'" Filename="',Filename,'"']);
|
|
{$ENDIF}
|
|
MarkPathAsSearched(SearchPath);
|
|
end;
|
|
Result:=Filename<>'';
|
|
end;
|
|
|
|
var
|
|
SearchPath: String;
|
|
SearchFile: String;
|
|
begin
|
|
{$IFDEF VerboseFindSourceFile}
|
|
debugln(['TMainIDE.FindSourceFile Filename="',AFilename,'" BaseDirectory="',BaseDirectory,'"']);
|
|
{$ENDIF}
|
|
|
|
if fsfMapTempToVirtualFiles in Flags then
|
|
begin
|
|
BaseDir:=GetTestBuildDirectory;
|
|
if FilenameIsAbsolute(AFilename)
|
|
and FileIsInPath(AFilename,BaseDir) then
|
|
begin
|
|
Result:=CreateRelativePath(AFilename,BaseDir);
|
|
if Project1.UnitInfoWithFilename(Result)<>nil then
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
if FilenameIsAbsolute(AFilename) then
|
|
begin
|
|
Result := AFilename;
|
|
if not FileExistsUTF8(Result) then
|
|
Result := '';
|
|
Exit;
|
|
end;
|
|
|
|
AlreadySearchedPaths:='';
|
|
BaseDir:=BaseDirectory;
|
|
GlobalMacroList.SubstituteStr(BaseDir);
|
|
BaseDir:=AppendPathDelim(TrimFilename(BaseDir));
|
|
|
|
// search file in base directory
|
|
Result:=TrimFilename(BaseDir+AFilename);
|
|
{$IFDEF VerboseFindSourceFile}
|
|
debugln(['TMainIDE.FindSourceFile trying Base "',Result,'"']);
|
|
{$ENDIF}
|
|
if FileExistsUTF8(Result) then exit;
|
|
MarkPathAsSearched(BaseDir);
|
|
|
|
// search file in debug path
|
|
if fsfUseDebugPath in Flags then begin
|
|
SearchPath:=EnvironmentOptions.DebuggerSearchPath;
|
|
GlobalMacroList.SubstituteStr(SearchPath);
|
|
SearchPath:=MergeSearchPaths(Project1.CompilerOptions.GetDebugPath(false),
|
|
SearchPath);
|
|
SearchPath:=TrimSearchPath(SearchPath,BaseDir);
|
|
if SearchInPath(SearchPath,AFilename,Result) then exit;
|
|
end;
|
|
|
|
CompiledSrcExt:=CodeToolBoss.GetCompiledSrcExtForDirectory(BaseDir);
|
|
StartUnitPath:=CodeToolBoss.GetCompleteSrcPathForDirectory(BaseDir);
|
|
StartUnitPath:=TrimSearchPath(StartUnitPath,BaseDir);
|
|
|
|
// if file is a pascal unit, search via unit and src paths
|
|
if FilenameIsPascalUnit(AFilename) then begin
|
|
// first search file in unit path
|
|
if SearchInPath(StartUnitPath,AFilename,Result) then exit;
|
|
|
|
// search unit in fpc source directory
|
|
Result:=CodeToolBoss.FindUnitInUnitSet(BaseDir,
|
|
ExtractFilenameOnly(AFilename));
|
|
{$IFDEF VerboseFindSourceFile}
|
|
debugln(['TMainIDE.FindSourceFile tried unitset Result=',Result]);
|
|
{$ENDIF}
|
|
if Result<>'' then exit;
|
|
end;
|
|
|
|
if fsfUseIncludePaths in Flags then begin
|
|
// search in include path
|
|
if (fsfSearchForProject in Flags) then
|
|
SearchPath:=Project1.CompilerOptions.GetIncludePath(false)
|
|
else
|
|
SearchPath:=CodeToolBoss.GetIncludePathForDirectory(BaseDir);
|
|
SearchPath:=TrimSearchPath(SearchPath,BaseDir);
|
|
if SearchInPath(StartUnitPath,AFilename,Result) then exit;
|
|
|
|
if not(fsfSkipPackages in Flags) then begin
|
|
// search include file in source directories of all required packages
|
|
SearchFile:=AFilename;
|
|
Result:=PkgBoss.FindIncludeFileInProjectDependencies(Project1,SearchFile);
|
|
{$IFDEF VerboseFindSourceFile}
|
|
debugln(['TMainIDE.FindSourceFile trying packages "',SearchPath,'" Result=',Result]);
|
|
{$ENDIF}
|
|
end;
|
|
if Result<>'' then exit;
|
|
|
|
Result:=SearchIndirectIncludeFile;
|
|
if Result<>'' then exit;
|
|
end;
|
|
|
|
Result:='';
|
|
end;
|
|
|
|
function TMainIDE.FileExistsInIDE(const Filename: string;
|
|
SearchFlags: TProjectFileSearchFlags): boolean;
|
|
begin
|
|
Result:=FileExistsUTF8(Filename)
|
|
or (Project1.UnitInfoWithFilename(Filename,SearchFlags)<>nil);
|
|
end;
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
procedure TMainIDE.OnDesignerGetSelectedComponentClass(Sender: TObject;
|
|
var RegisteredComponent: TRegisteredComponent);
|
|
begin
|
|
RegisteredComponent:=IDEComponentPalette.Selected;
|
|
end;
|
|
|
|
procedure TMainIDE.OnDesignerComponentAdded(Sender: TObject);
|
|
var
|
|
Grid: TOICustomPropertyGrid;
|
|
Row: TOIPropertyGridRow;
|
|
begin
|
|
TComponentPalette(IDEComponentPalette).DoAfterComponentAdded;
|
|
if EnvironmentOptions.CreateComponentFocusNameProperty
|
|
and (ObjectInspector1<>nil) then begin
|
|
if (ObjectInspector1.ShowFavorites) and (EnvironmentOptions.SwitchToFavoritesOITab) then
|
|
Grid:=ObjectInspector1.FavouriteGrid
|
|
else
|
|
Grid:=ObjectInspector1.PropertyGrid;
|
|
ObjectInspector1.ActivateGrid(Grid);
|
|
Row:=Grid.GetRowByPath('Name');
|
|
if Row<>nil then begin
|
|
Grid.ItemIndex:=Row.Index;
|
|
ObjectInspector1.FocusGrid(Grid);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnDesignerSetDesigning(Sender: TObject;
|
|
Component: TComponent; Value: boolean);
|
|
begin
|
|
SetDesigning(Component,Value);
|
|
end;
|
|
|
|
procedure TMainIDE.OnDesignerShowOptions(Sender: TObject);
|
|
begin
|
|
DoOpenIDEOptions(TFormEditorOptionsFrame);
|
|
end;
|
|
|
|
procedure TMainIDE.OnDesignerPasteComponent(Sender: TObject;
|
|
LookupRoot: TComponent; TxtCompStream: TStream; ParentControl: TWinControl;
|
|
var NewComponent: TComponent);
|
|
var
|
|
NewClassName: String;
|
|
ARegComp: TRegisteredComponent;
|
|
BinCompStream: TMemoryStream;
|
|
begin
|
|
DebugLn('TMainIDE.OnDesignerPasteComponent A');
|
|
NewComponent:=nil;
|
|
|
|
// check the class of the new component
|
|
NewClassName:=FindLFMClassName(TxtCompStream);
|
|
|
|
// check if component class is registered
|
|
ARegComp:=IDEComponentPalette.FindComponent(NewClassName);
|
|
if ARegComp=nil then begin
|
|
MessageDlg(lisClassNotFound,
|
|
Format(lisClassIsNotARegisteredComponentClassUnableToPaste, ['"',
|
|
NewClassName, '"', #13]),
|
|
mtError,[mbCancel],0);
|
|
exit;
|
|
end;
|
|
|
|
// check if there is a valid parent
|
|
if (ParentControl=nil) and ARegComp.IsTControl then begin
|
|
MessageDlg(lisControlNeedsParent,
|
|
Format(lisTheClassIsATControlAndCanNotBePastedOntoANonContro, ['"',
|
|
NewClassName, '"', #13]),
|
|
mtError,[mbCancel],0);
|
|
exit;
|
|
end;
|
|
|
|
// convert text to binary format
|
|
BinCompStream:=TMemoryStream.Create;
|
|
try
|
|
try
|
|
LRSObjectTextToBinary(TxtCompStream,BinCompStream);
|
|
except
|
|
on E: Exception do begin
|
|
MessageDlg(lisConversionError,
|
|
Format(lisUnableToConvertComponentTextIntoBinaryFormat, [#13,
|
|
E.Message]),
|
|
mtError,[mbCancel],0);
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
BinCompStream.Position:=0;
|
|
|
|
// create the component
|
|
NewComponent := FormEditor1.CreateChildComponentFromStream(BinCompStream,
|
|
ARegComp.ComponentClass,LookupRoot,ParentControl);
|
|
if NewComponent=nil then begin
|
|
DebugLn('TMainIDE.OnDesignerPasteComponent FAILED');
|
|
exit;
|
|
end;
|
|
|
|
finally
|
|
BinCompStream.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnDesignerPropertiesChanged(Sender: TObject);
|
|
begin
|
|
ObjectInspector1.RefreshPropertyValues;
|
|
end;
|
|
|
|
procedure TMainIDE.OnDesignerPersistentDeleted(Sender: TObject;
|
|
APersistent: TPersistent);
|
|
// important: APersistent was freed, do not access it
|
|
var
|
|
CurDesigner: TDesigner;
|
|
begin
|
|
CurDesigner := TDesigner(Sender);
|
|
if dfDestroyingForm in CurDesigner.Flags then exit;
|
|
ObjectInspector1.FillPersistentComboBox;
|
|
end;
|
|
|
|
procedure TMainIDE.OnPropHookPersistentDeleting(APersistent: TPersistent);
|
|
var
|
|
ActiveForm: TCustomForm;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
ActiveSrcEdit: TSourceEditor;
|
|
OwnerClassName: string;
|
|
CurDesigner: TDesigner;
|
|
begin
|
|
if not (APersistent is TComponent) then exit;
|
|
//DebugLn(['TMainIDE.OnPropHookPersistentDeleting ',dbgsName(APersistent)]);
|
|
CurDesigner:=TDesigner(FindRootDesigner(TComponent(APersistent)));
|
|
if CurDesigner=nil then exit;
|
|
|
|
if dfDestroyingForm in CurDesigner.Flags then exit;
|
|
|
|
if not BeginCodeTool(CurDesigner,ActiveSrcEdit,ActiveUnitInfo,
|
|
[ctfSwitchToFormSource]) then exit;
|
|
ActiveForm:=CurDesigner.Form;
|
|
if ActiveForm=nil then
|
|
RaiseException('[TMainIDE.OnPropHookPersistentDeleting] Error: TDesigner without a form');
|
|
// find source for form
|
|
ActiveUnitInfo:=Project1.UnitWithComponent(CurDesigner.LookupRoot);
|
|
if ActiveUnitInfo=nil then begin
|
|
RaiseException('[TMainIDE.OnPropHookPersistentDeleting] Error: form without source');
|
|
end;
|
|
if APersistent is TComponent then begin
|
|
// mark references modified
|
|
if APersistent is TComponent then
|
|
MarkUnitsModifiedUsingSubComponent(TComponent(APersistent));
|
|
|
|
// remember cursor position
|
|
SourceEditorManager.AddJumpPointClicked(Self);
|
|
|
|
// remove component definition from owner source
|
|
OwnerClassName:=CurDesigner.LookupRoot.ClassName;
|
|
//DebugLn(['TMainIDE.OnPropHookPersistentDeleting ',dbgsName(APersistent),' OwnerClassName=',OwnerClassName]);
|
|
CodeToolBoss.RemovePublishedVariable(ActiveUnitInfo.Source,OwnerClassName,
|
|
TComponent(APersistent).Name,false);
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnDesignerModified(Sender: TObject);
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
CurDesigner: TDesigner absolute Sender;
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
if dfDestroyingForm in CurDesigner.Flags then Exit;
|
|
AnUnitInfo := Project1.UnitWithComponent(CurDesigner.LookupRoot);
|
|
if AnUnitInfo <> nil then
|
|
begin
|
|
AnUnitInfo.Modified := True;
|
|
if AnUnitInfo.Loaded then
|
|
begin
|
|
if AnUnitInfo.OpenEditorInfoCount > 0 then
|
|
begin
|
|
SrcEdit := TSourceEditor(AnUnitInfo.OpenEditorInfo[0].EditorComponent);
|
|
SrcEdit.Modified := True;
|
|
{$IFDEF VerboseDesignerModified}
|
|
DumpStack;
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnControlSelectionChanged(Sender: TObject; ForceUpdate: Boolean);
|
|
var
|
|
NewSelection: TPersistentSelectionList;
|
|
i: integer;
|
|
begin
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TMainIDE.OnControlSelectionChanged]');
|
|
{$ENDIF}
|
|
if (TheControlSelection = nil) or (FormEditor1 = nil) then Exit;
|
|
|
|
NewSelection := TPersistentSelectionList.Create;
|
|
NewSelection.ForceUpdate := ForceUpdate;
|
|
for i := 0 to TheControlSelection.Count - 1 do
|
|
NewSelection.Add(TheControlSelection[i].Persistent);
|
|
FormEditor1.Selection := NewSelection;
|
|
NewSelection.Free;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TMainIDE.OnControlSelectionChanged] END');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TMainIDE.OnControlSelectionPropsChanged(Sender: TObject);
|
|
begin
|
|
if (TheControlSelection=nil) or (FormEditor1=nil) then exit;
|
|
if not TheControlSelection.Equals(ObjectInspector1.Selection) then
|
|
ObjectInspector1.SaveChanges;
|
|
ObjectInspector1.RefreshPropertyValues;
|
|
end;
|
|
|
|
procedure TMainIDE.OnControlSelectionFormChanged(Sender: TObject; OldForm,
|
|
NewForm: TCustomForm);
|
|
begin
|
|
if (TheControlSelection=nil) or (FormEditor1=nil) then exit;
|
|
if OldForm<>nil then
|
|
OldForm.Invalidate;
|
|
if NewForm<>nil then
|
|
NewForm.Invalidate;
|
|
UpdateIDEComponentPalette;
|
|
end;
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
procedure TMainIDE.UnitDependenciesViewAccessingSources(Sender: TObject);
|
|
begin
|
|
SaveSourceEditorChangesToCodeCache(nil);
|
|
end;
|
|
|
|
function TMainIDE.UnitDependenciesViewGetProjectMainFilename(Sender: TObject
|
|
): string;
|
|
begin
|
|
if Project1.MainUnitID>=0 then
|
|
Result:=Project1.MainUnitInfo.Filename
|
|
else
|
|
Result:='';
|
|
end;
|
|
|
|
procedure TMainIDE.UnitDependenciesViewOpenFile(Sender: TObject;
|
|
const Filename: string);
|
|
begin
|
|
DoOpenEditorFile(Filename,-1,-1,[]);
|
|
end;
|
|
|
|
procedure TMainIDE.OnCodeExplorerGetDirectivesTree(Sender: TObject;
|
|
var ADirectivesTool: TDirectivesTool);
|
|
var
|
|
ActiveUnitInfo: TUnitInfo;
|
|
ActiveSrcEdit: TSourceEditor;
|
|
begin
|
|
ADirectivesTool:=nil;
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
CodeToolBoss.ExploreDirectives(ActiveUnitInfo.Source,ADirectivesTool);
|
|
end;
|
|
|
|
procedure TMainIDE.OnCodeExplorerJumpToCode(Sender: TObject;
|
|
const Filename: string; const Caret: TPoint; TopLine: integer);
|
|
begin
|
|
DoJumpToSourcePosition(Filename,Caret.X,Caret.Y,TopLine,[jfAddJumpPoint, jfFocusEditor]);
|
|
end;
|
|
|
|
procedure TMainIDE.OnCodeExplorerShowOptions(Sender: TObject);
|
|
begin
|
|
DoOpenIDEOptions(TCodeExplorerUpdateOptionsFrame);
|
|
end;
|
|
|
|
procedure TMainIDE.OnCodeToolNeedsExternalChanges(Manager: TCodeToolManager;
|
|
var Abort: boolean);
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
begin
|
|
Abort:=not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]);
|
|
end;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
function TMainIDE.InitCodeToolBoss: boolean;
|
|
// initialize the CodeToolBoss, which is the frontend for the codetools.
|
|
// - sets a basic set of compiler macros
|
|
var
|
|
AFilename: string;
|
|
InteractiveSetup: boolean;
|
|
Note: string;
|
|
CfgCache: TFPCTargetConfigCache;
|
|
begin
|
|
Result:=true;
|
|
InteractiveSetup:=true;
|
|
OpenEditorsOnCodeToolChange:=false;
|
|
|
|
// load caches
|
|
MainBuildBoss.LoadFPCDefinesCaches;
|
|
|
|
CodeToolBoss.DefinePool.OnProgress:=@CodeToolBossProgress;
|
|
CodeToolBoss.SourceCache.ExpirationTimeInDays:=365;
|
|
CodeToolBoss.SourceCache.OnEncodeSaving:=@OnCodeBufferEncodeSaving;
|
|
CodeToolBoss.SourceCache.OnDecodeLoaded:=@OnCodeBufferDecodeLoaded;
|
|
CodeToolBoss.SourceCache.DefaultEncoding:=EncodingUTF8;
|
|
CodeToolBoss.DefineTree.OnGetVirtualDirectoryAlias:=
|
|
@CodeToolBossGetVirtualDirectoryAlias;
|
|
CodeToolBoss.DefineTree.OnGetVirtualDirectoryDefines:=
|
|
@CodeToolBossGetVirtualDirectoryDefines;
|
|
CodeToolBoss.DefineTree.OnPrepareTree:=@CodeToolBossPrepareTree;
|
|
|
|
CodeToolBoss.DefineTree.MacroFunctions.AddExtended(
|
|
'PROJECT',nil,@CTMacroFunctionProject);
|
|
|
|
CodeToolsOpts.AssignTo(CodeToolBoss);
|
|
if (not FileExistsCached(EnvironmentOptions.GetCompilerFilename)) then begin
|
|
DebugLn('');
|
|
DebugLn('NOTE: Compiler filename not set! (see Environment / Options ... / Environment / Files)');
|
|
end;
|
|
|
|
if (EnvironmentOptions.LazarusDirectory='')
|
|
or not DirPathExists(EnvironmentOptions.LazarusDirectory) then begin
|
|
DebugLn('');
|
|
DebugLn(
|
|
'NOTE: Lazarus source directory not set! (see Environment / Options ... / Environment / Files)');
|
|
end;
|
|
if (EnvironmentOptions.FPCSourceDirectory='') then
|
|
begin
|
|
// Note: the FPCSourceDirectory can contain the macro FPCVer, which depend
|
|
// on the compiler. Do not check if file exists here.
|
|
DebugLn('');
|
|
DebugLn('NOTE: FPC source directory not set! (see Environment / Options ... / Environment / Files)');
|
|
end;
|
|
|
|
// create a test unit needed to get from the compiler all macros and search paths
|
|
CodeToolBoss.FPCDefinesCache.TestFilename:=CreateCompilerTestPascalFilename;
|
|
MainBuildBoss.UpdateEnglishErrorMsgFilename;
|
|
|
|
if InteractiveSetup then
|
|
begin
|
|
if (not ShowSetupDialog)
|
|
and ((CheckLazarusDirectoryQuality(EnvironmentOptions.LazarusDirectory,Note)=sddqInvalid)
|
|
or (CheckCompilerQuality(EnvironmentOptions.GetCompilerFilename,Note,
|
|
CodeToolBoss.FPCDefinesCache.TestFilename)=sddqInvalid))
|
|
then
|
|
ShowSetupDialog:=true;
|
|
if (not ShowSetupDialog) then
|
|
begin
|
|
CfgCache:=CodeToolBoss.FPCDefinesCache.ConfigCaches.Find(
|
|
EnvironmentOptions.GetCompilerFilename,'','','',true);
|
|
if CheckFPCSrcDirQuality(EnvironmentOptions.GetFPCSourceDirectory,Note,
|
|
CfgCache.GetFPCVer)=sddqInvalid
|
|
then
|
|
ShowSetupDialog:=true;
|
|
end;
|
|
if ShowSetupDialog then
|
|
if ShowInitialSetupDialog<>mrOk then
|
|
exit(false);
|
|
end;
|
|
|
|
// set global macros
|
|
with CodeToolBoss.GlobalValues do begin
|
|
Variables[ExternalMacroStart+'LazarusDir']:=EnvironmentOptions.LazarusDirectory;
|
|
Variables[ExternalMacroStart+'ProjPath']:=VirtualDirectory;
|
|
Variables[ExternalMacroStart+'LCLWidgetType']:=LCLPlatformDirNames[GetDefaultLCLWidgetType];
|
|
Variables[ExternalMacroStart+'FPCSrcDir']:=EnvironmentOptions.GetFPCSourceDirectory;
|
|
end;
|
|
|
|
// the first template is the "use default" flag
|
|
CreateUseDefaultsFlagTemplate;
|
|
|
|
MainBuildBoss.SetBuildTargetProject1(false);
|
|
|
|
// load include file relationships
|
|
AFilename:=AppendPathDelim(GetPrimaryConfigPath)+CodeToolsIncludeLinkFile;
|
|
if FileExistsCached(AFilename) then
|
|
CodeToolBoss.SourceCache.LoadIncludeLinksFromFile(AFilename);
|
|
|
|
with CodeToolBoss do begin
|
|
WriteExceptions:=true;
|
|
CatchExceptions:=true;
|
|
OnGatherExternalChanges:=@OnCodeToolNeedsExternalChanges;
|
|
OnBeforeApplyChanges:=@OnBeforeCodeToolBossApplyChanges;
|
|
OnAfterApplyChanges:=@OnAfterCodeToolBossApplyChanges;
|
|
OnSearchUsedUnit:=@OnCodeToolBossSearchUsedUnit;
|
|
OnFindDefineProperty:=@OnCodeToolBossFindDefineProperty;
|
|
OnGetMethodName:=@OnCodeToolBossGetMethodName;
|
|
OnGetIndenterExamples:=@OnCodeToolBossGetIndenterExamples;
|
|
end;
|
|
|
|
CodeToolsOpts.AssignGlobalDefineTemplatesToTree(CodeToolBoss.DefineTree);
|
|
|
|
CompilerParseStampIncreased:=@OnCompilerParseStampIncreased;
|
|
|
|
// codetools consistency check
|
|
CodeToolBoss.ConsistencyCheck;
|
|
end;
|
|
|
|
procedure TMainIDE.ActivateCodeToolAbortableMode;
|
|
begin
|
|
if ToolStatus=itNone then
|
|
RaiseException('TMainIDE.ActivateCodeToolAbortableMode Error 1');
|
|
ToolStatus:=itCodeTools;
|
|
CodeToolBoss.OnCheckAbort:=@OnCodeToolBossCheckAbort;
|
|
CodeToolBoss.Abortable:=true;
|
|
end;
|
|
|
|
function TMainIDE.BeginCodeTools: boolean;
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
begin
|
|
Result:=BeginCodeTool(nil,ActiveSrcEdit,ActiveUnitInfo,
|
|
[ctfSourceEditorNotNeeded]);
|
|
end;
|
|
|
|
procedure TMainIDE.OnBeforeCodeToolBossApplyChanges(Manager: TCodeToolManager;
|
|
var Abort: boolean);
|
|
// the CodeToolBoss built a list of Sources that will be modified
|
|
// 1. open all of them in the source notebook
|
|
// 2. lock the editors to reduce repaints and undo steps
|
|
var
|
|
i: integer;
|
|
Flags: TOpenFlags;
|
|
CodeBuf: TCodeBuffer;
|
|
begin
|
|
if OpenEditorsOnCodeToolChange then begin
|
|
// open all sources in editor
|
|
for i:=0 to Manager.SourceChangeCache.BuffersToModifyCount-1 do begin
|
|
CodeBuf:=Manager.SourceChangeCache.BuffersToModify[i];
|
|
|
|
// do not open lpr file
|
|
if (not OpenMainSourceOnCodeToolChange)
|
|
and (Project1<>nil) and (Project1.MainUnitInfo<>nil)
|
|
and (CompareFilenames(Project1.MainFilename,CodeBuf.Filename)=0) then
|
|
continue;
|
|
|
|
//DebugLn(['TMainIDE.OnBeforeCodeToolBossApplyChanges i=',i,' ',CodeBUf.Filename]);
|
|
Flags:=[ofOnlyIfExists,ofDoNotLoadResource];
|
|
if CodeBuf.IsVirtual then
|
|
Include(Flags,ofVirtualFile);
|
|
if DoOpenEditorFile(Manager.SourceChangeCache.BuffersToModify[i].Filename,
|
|
-1,-1,Flags)<>mrOk then
|
|
begin
|
|
Abort:=true;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
// lock all editors
|
|
SourceEditorManager.LockAllEditorsInSourceChangeCache;
|
|
end;
|
|
|
|
procedure TMainIDE.OnAfterCodeToolBossApplyChanges(Manager: TCodeToolManager);
|
|
var
|
|
i: Integer;
|
|
SrcBuf: TCodeBuffer;
|
|
AnUnitInfo: TUnitInfo;
|
|
MsgResult: TModalResult;
|
|
begin
|
|
for i:=0 to CodeToolBoss.SourceChangeCache.BuffersToModifyCount-1 do begin
|
|
SrcBuf:=CodeToolBoss.SourceChangeCache.BuffersToModify[i];
|
|
AnUnitInfo:=Project1.UnitInfoWithFilename(SrcBuf.Filename);
|
|
if AnUnitInfo<>nil then
|
|
AnUnitInfo.Modified:=true;
|
|
|
|
if SaveClosedSourcesOnCodeToolChange
|
|
and (not SrcBuf.IsVirtual)
|
|
and ((AnUnitInfo=nil) or (AnUnitInfo.OpenEditorInfoCount = 0)) then
|
|
begin
|
|
// save closed file (closed = not open in editor)
|
|
MsgResult:=SaveCodeBuffer(SrcBuf);
|
|
if MsgResult=mrAbort then break;
|
|
end;
|
|
end;
|
|
SourceEditorManager.UnlockAllEditorsInSourceChangeCache;
|
|
end;
|
|
|
|
function TMainIDE.OnCodeToolBossSearchUsedUnit(const SrcFilename: string;
|
|
const TheUnitName, TheUnitInFilename: string): TCodeBuffer;
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
Result:=nil;
|
|
// check if SrcFilename is project file
|
|
AnUnitInfo:=Project1.ProjectUnitWithFilename(SrcFilename);
|
|
if AnUnitInfo=nil then exit;
|
|
// SrcFilename is a project file
|
|
// -> search virtual project files
|
|
AnUnitInfo:=Project1.ProjectUnitWithUnitname(TheUnitName);
|
|
if AnUnitInfo=nil then exit;
|
|
// virtual unit found
|
|
Result:=AnUnitInfo.Source;
|
|
end;
|
|
|
|
function TMainIDE.OnCodeToolBossCheckAbort: boolean;
|
|
begin
|
|
Result:=true;
|
|
if ToolStatus<>itCodeTools then exit;
|
|
Application.ProcessMessages;
|
|
Result:=ToolStatus<>itCodeTools;
|
|
end;
|
|
|
|
procedure TMainIDE.CodeToolBossGetVirtualDirectoryAlias(Sender: TObject;
|
|
var RealDir: string);
|
|
begin
|
|
if (Project1<>nil) and (Project1.ProjectDirectory<>'') then
|
|
RealDir:=Project1.ProjectDirectory;
|
|
end;
|
|
|
|
procedure TMainIDE.CodeToolBossGetVirtualDirectoryDefines(DefTree: TDefineTree;
|
|
DirDef: TDirectoryDefines);
|
|
begin
|
|
if (Project1<>nil) and Project1.IsVirtual then
|
|
Project1.GetVirtualDefines(DefTree,DirDef);
|
|
end;
|
|
|
|
procedure TMainIDE.OnCodeToolBossFindDefineProperty(Sender: TObject;
|
|
const PersistentClassName, AncestorClassName, Identifier: string;
|
|
var IsDefined: boolean);
|
|
begin
|
|
FormEditor1.FindDefineProperty(PersistentClassName,AncestorClassName,
|
|
Identifier,IsDefined);
|
|
end;
|
|
|
|
procedure TMainIDE.OnCodeBufferDecodeLoaded(Code: TCodeBuffer;
|
|
const Filename: string; var Source, DiskEncoding, MemEncoding: string);
|
|
begin
|
|
//DebugLn(['TMainIDE.OnCodeBufferDecodeLoaded Filename=',Filename,' Encoding=',GuessEncoding(Source)]);
|
|
DiskEncoding:='';
|
|
if InputHistories<>nil then
|
|
DiskEncoding:=InputHistories.FileEncodings[Filename];
|
|
if DiskEncoding='' then
|
|
DiskEncoding:=GuessEncoding(Source);
|
|
MemEncoding:=EncodingUTF8;
|
|
if (DiskEncoding<>MemEncoding) then begin
|
|
{$IFDEF VerboseIDEEncoding}
|
|
DebugLn(['TMainIDE.OnCodeBufferDecodeLoaded Filename=',Filename,' Disk=',DiskEncoding,' to Mem=',MemEncoding]);
|
|
{$ENDIF}
|
|
Source:=ConvertEncoding(Source,DiskEncoding,MemEncoding);
|
|
//DebugLn(['TMainIDE.OnCodeBufferDecodeLoaded ',Source]);
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnCodeBufferEncodeSaving(Code: TCodeBuffer;
|
|
const Filename: string; var Source: string);
|
|
begin
|
|
if (Code.DiskEncoding<>'') and (Code.MemEncoding<>'')
|
|
and (Code.DiskEncoding<>Code.MemEncoding) then begin
|
|
{$IFDEF VerboseIDEEncoding}
|
|
DebugLn(['TMainIDE.OnCodeBufferEncodeSaving Filename=',Code.Filename,' Mem=',Code.MemEncoding,' to Disk=',Code.DiskEncoding]);
|
|
{$ENDIF}
|
|
Source:=ConvertEncoding(Source,Code.MemEncoding,Code.DiskEncoding);
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.CodeToolBossPrepareTree(Sender: TObject);
|
|
begin
|
|
if FIDECodeToolsDefines=ctdNeedUpdate then begin
|
|
FIDECodeToolsDefines:=ctdUpdating;
|
|
if Project1<>nil then
|
|
Project1.DefineTemplates.AllChanged;
|
|
PkgBoss.RebuildDefineTemplates;
|
|
FIDECodeToolsDefines:=ctdReady;
|
|
//DebugLn('TMainIDE.CodeToolBossPrepareTree CompilerGraphStamp=',dbgs(CompilerGraphStamp));
|
|
{$IFDEF VerboseAddProjPkg}
|
|
DebugLn(['TMainIDE.CodeToolBossPrepareTree 1 "',CodeToolBoss.GetUnitPathForDirectory('',true),'"']);
|
|
DebugLn(['TMainIDE.CodeToolBossPrepareTree 2 "',CodeToolBoss.GetUnitPathForDirectory('',false),'"']);
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.CodeToolBossProgress(Sender: TObject; Index,
|
|
MaxIndex: integer; const Msg: string; var Abort: boolean);
|
|
begin
|
|
//DebugLn(['TMainIDE.CodeToolBossProgress ',Index,' ',MaxIndex]);
|
|
end;
|
|
|
|
procedure TMainIDE.OnCodeToolBossGetIndenterExamples(Sender: TObject;
|
|
Code: TCodeBuffer; Step: integer; var CodeBuffers: TFPList;
|
|
var ExpandedFilenames: TStrings);
|
|
var
|
|
ActiveFilename: string;
|
|
|
|
procedure AddCode(Code: TCodeBuffer);
|
|
begin
|
|
if Code=nil then exit;
|
|
if CompareFilenames(ActiveFilename,Code.Filename)=0 then exit;
|
|
if CodeBuffers=nil then CodeBuffers:=TFPList.Create;
|
|
CodeBuffers.Add(Code);
|
|
end;
|
|
|
|
procedure AddFile(const Filename: string);
|
|
begin
|
|
if Filename='' then exit;
|
|
if CompareFilenames(ActiveFilename,Filename)=0 then exit;
|
|
if ExpandedFilenames=nil then ExpandedFilenames:=TStringList.Create;
|
|
ExpandedFilenames.Add(Filename);
|
|
end;
|
|
|
|
procedure AddUnit(AnUnitInfo: TUnitInfo);
|
|
begin
|
|
if AnUnitInfo.Source<>nil then
|
|
AddCode(AnUnitInfo.Source)
|
|
else
|
|
AddFile(AnUnitInfo.Filename);
|
|
end;
|
|
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
Owners: TFPList;
|
|
i: Integer;
|
|
AProject: TProject;
|
|
APackage: TLazPackage;
|
|
j: Integer;
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
if Step>0 then exit;
|
|
ActiveFilename:='';
|
|
SrcEdit:=SourceEditorManager.GetActiveSE;
|
|
if SrcEdit<>nil then
|
|
ActiveFilename:=SrcEdit.FileName;
|
|
if CodeToolsOpts.IndentContextSensitive and (Code<>Nil) then begin
|
|
Owners:=PkgBoss.GetPossibleOwnersOfUnit(Code.Filename,[piosfIncludeSourceDirectories]);
|
|
try
|
|
if Owners<>nil then begin
|
|
for i:=0 to Owners.Count-1 do begin
|
|
if TObject(Owners[i]) is TProject then begin
|
|
AProject:=TProject(Owners[i]);
|
|
if AProject.MainUnitInfo<>nil then
|
|
AddUnit(AProject.MainUnitInfo);
|
|
AnUnitInfo:=AProject.FirstPartOfProject;
|
|
while AnUnitInfo<>nil do begin
|
|
if AnUnitInfo<>AProject.MainUnitInfo then
|
|
AddUnit(AnUnitInfo);
|
|
AnUnitInfo:=AnUnitInfo.NextPartOfProject;
|
|
end;
|
|
end else if TObject(Owners[i]) is TLazPackage then begin
|
|
APackage:=TLazPackage(Owners[i]);
|
|
for j:=0 to APackage.FileCount-1 do begin
|
|
if APackage.Files[j].FileType in PkgFileRealUnitTypes then
|
|
AddFile(APackage.Files[j].GetFullFilename);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
Owners.Free;
|
|
end;
|
|
end;
|
|
if FilenameIsAbsolute(CodeToolsOpts.IndentationFileName)
|
|
then
|
|
AddFile(CodeToolsOpts.IndentationFileName);
|
|
end;
|
|
|
|
function TMainIDE.OnCodeToolBossGetMethodName(const Method: TMethod;
|
|
PropOwner: TObject): String;
|
|
var
|
|
JITMethod: TJITMethod;
|
|
LookupRoot: TPersistent;
|
|
begin
|
|
if Method.Code<>nil then begin
|
|
if Method.Data<>nil then
|
|
Result:=TObject(Method.Data).MethodName(Method.Code)
|
|
else
|
|
Result:='';
|
|
end else if IsJITMethod(Method) then begin
|
|
JITMethod:=TJITMethod(Method.Data);
|
|
Result:=JITMethod.TheMethodName;
|
|
if PropOwner is TComponent then begin
|
|
LookupRoot:=GetLookupRootForComponent(TComponent(PropOwner));
|
|
if LookupRoot is TComponent then begin
|
|
//DebugLn(['TMainIDE.OnPropHookGetMethodName ',Result,' ',dbgsName(GlobalDesignHook.LookupRoot),' ',dbgsName(JITMethod.TheClass)]);
|
|
if (LookupRoot.ClassType<>JITMethod.TheClass) then begin
|
|
Result:=JITMethod.TheClass.ClassName+'.'+Result;
|
|
end;
|
|
end;
|
|
end;
|
|
end else
|
|
Result:='';
|
|
{$IFDEF VerboseDanglingComponentEvents}
|
|
if IsJITMethod(Method) then
|
|
DebugLn(['TMainIDE.OnPropHookGetMethodName ',Result,' ',IsJITMethod(Method)]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TMainIDE.OnCompilerParseStampIncreased;
|
|
begin
|
|
if FIDECodeToolsDefines=ctdUpdating then exit;
|
|
{$IFDEF VerboseAddProjPkg}
|
|
DebugLn(['TMainIDE.OnCompilerParseStampIncreased ']);
|
|
{$ENDIF}
|
|
FIDECodeToolsDefines:=ctdNeedUpdate;
|
|
CodeToolBoss.DefineTree.ClearCache;
|
|
end;
|
|
|
|
function TMainIDE.CTMacroFunctionProject(Data: Pointer): boolean;
|
|
var
|
|
FuncData: PReadFunctionData;
|
|
Param: String;
|
|
begin
|
|
Result:=true;
|
|
if Project1=nil then exit;
|
|
FuncData:=PReadFunctionData(Data);
|
|
Param:=FuncData^.Param;
|
|
//debugln('TMainIDE.MacroFunctionProject A Param="',Param,'"');
|
|
if SysUtils.CompareText(Param,'SrcPath')=0 then
|
|
FuncData^.Result:=Project1.CompilerOptions.GetSrcPath(false)
|
|
else if SysUtils.CompareText(Param,'IncPath')=0 then
|
|
FuncData^.Result:=Project1.CompilerOptions.GetIncludePath(false)
|
|
else if SysUtils.CompareText(Param,'UnitPath')=0 then
|
|
FuncData^.Result:=Project1.CompilerOptions.GetUnitPath(false)
|
|
else begin
|
|
FuncData^.Result:='<unknown parameter for CodeTools Macro project:"'+Param+'">';
|
|
debugln('TMainIDE.MacroFunctionProject WARNING: ',FuncData^.Result);
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.SaveSourceEditorChangesToCodeCache(PageIndex: integer): boolean;
|
|
begin
|
|
Result := SaveSourceEditorChangesToCodeCache(
|
|
SourceEditorManager.ActiveSourceWindow.FindSourceEditorWithPageIndex(PageIndex));
|
|
end;
|
|
|
|
function TMainIDE.SaveSourceEditorChangesToCodeCache(AEditor: TSourceEditorInterface): boolean;
|
|
// save all open sources to code tools cache
|
|
|
|
procedure SaveChanges(SaveEditor: TSourceEditorInterface);
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
AnUnitInfo := Project1.UnitWithEditorComponent(SaveEditor);
|
|
if (AnUnitInfo<>nil) then
|
|
begin
|
|
SaveSourceEditorChangesToCodeCache:=true;
|
|
if SaveEditor.NeedsUpdateCodeBuffer then
|
|
begin
|
|
SaveEditor.UpdateCodeBuffer;
|
|
AnUnitInfo.Modified:=true;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
i: integer;
|
|
begin
|
|
Result:=false;
|
|
if AEditor = nil then begin
|
|
for i:=0 to SourceEditorManager.SourceEditorCount - 1 do
|
|
SaveChanges(SourceEditorManager.SourceEditors[i]);
|
|
end else begin
|
|
SaveChanges(AEditor);
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.BeginCodeTool(var ActiveSrcEdit: TSourceEditor;
|
|
out ActiveUnitInfo: TUnitInfo; Flags: TCodeToolsFlags): boolean;
|
|
begin
|
|
Result:=BeginCodeTool(nil,ActiveSrcEdit,ActiveUnitInfo,Flags);
|
|
end;
|
|
|
|
function TMainIDE.BeginCodeTool(ADesigner: TDesigner;
|
|
var ActiveSrcEdit: TSourceEditor; out ActiveUnitInfo: TUnitInfo;
|
|
Flags: TCodeToolsFlags): boolean;
|
|
begin
|
|
Result:=false;
|
|
if ctfUseGivenSourceEditor in Flags then begin
|
|
ActiveUnitInfo := Project1.EditorInfoWithEditorComponent(ActiveSrcEdit).UnitInfo;
|
|
end
|
|
else begin
|
|
ActiveSrcEdit:=nil;
|
|
ActiveUnitInfo:=nil;
|
|
end;
|
|
|
|
// check global stati
|
|
if (ToolStatus in [itCodeTools,itCodeToolAborting]) then begin
|
|
debugln('TMainIDE.BeginCodeTool impossible ',dbgs(ord(ToolStatus)));
|
|
exit;
|
|
end;
|
|
if (not (ctfSourceEditorNotNeeded in Flags)) and (SourceEditorManager.SourceEditorCount=0)
|
|
then begin
|
|
DebugLn('TMainIDE.BeginCodeTool no source editor');
|
|
exit;
|
|
end;
|
|
|
|
// check source editor
|
|
if not (ctfUseGivenSourceEditor in Flags) then begin
|
|
if ctfSwitchToFormSource in Flags then
|
|
DoSwitchToFormSrc(ADesigner,ActiveSrcEdit,ActiveUnitInfo)
|
|
else if ADesigner<>nil then
|
|
GetDesignerUnit(ADesigner,ActiveSrcEdit,ActiveUnitInfo)
|
|
else
|
|
GetCurrentUnit(ActiveSrcEdit,ActiveUnitInfo);
|
|
end;
|
|
if (not (ctfSourceEditorNotNeeded in Flags)) and
|
|
((ActiveSrcEdit=nil) or (ActiveUnitInfo=nil))
|
|
then exit;
|
|
|
|
// init codetools
|
|
SaveSourceEditorChangesToCodeCache(nil);
|
|
if ActiveSrcEdit<>nil then begin
|
|
CodeToolBoss.VisibleEditorLines:=ActiveSrcEdit.EditorComponent.LinesInWindow;
|
|
CodeToolBoss.TabWidth:=ActiveSrcEdit.EditorComponent.TabWidth;
|
|
CodeToolBoss.IndentSize:=ActiveSrcEdit.EditorComponent.BlockIndent;
|
|
end else begin
|
|
CodeToolBoss.VisibleEditorLines:=25;
|
|
CodeToolBoss.TabWidth:=EditorOpts.TabWidth;
|
|
CodeToolBoss.IndentSize:=EditorOpts.BlockIndent;
|
|
end;
|
|
|
|
if ctfActivateAbortMode in Flags then
|
|
ActivateCodeToolAbortableMode;
|
|
|
|
Result:=true;
|
|
end;
|
|
|
|
function TMainIDE.DoJumpToSourcePosition(const Filename: string; NewX, NewY,
|
|
NewTopLine: integer; Flags: TJumpToCodePosFlags = [jfFocusEditor]): TModalResult;
|
|
var
|
|
CodeBuffer: TCodeBuffer;
|
|
aFilename: String;
|
|
begin
|
|
Result:=mrCancel;
|
|
aFilename:=Filename;
|
|
if not (jfDoNotExpandFilename in Flags) then
|
|
aFilename:=TrimAndExpandFilename(aFilename);
|
|
CodeBuffer:=CodeToolBoss.LoadFile(aFilename,true,false);
|
|
if CodeBuffer=nil then exit;
|
|
Result:=DoJumpToCodePosition(nil,nil,CodeBuffer,NewX,NewY,NewTopLine, Flags);
|
|
end;
|
|
|
|
function TMainIDE.DoJumpToCodePosition(ActiveSrcEdit: TSourceEditorInterface;
|
|
ActiveUnitInfo: TUnitInfo; NewSource: TCodeBuffer; NewX, NewY, NewTopLine: integer;
|
|
Flags: TJumpToCodePosFlags): TModalResult;
|
|
var
|
|
SrcEdit, NewSrcEdit: TSourceEditor;
|
|
AnEditorInfo: TUnitEditorInfo;
|
|
s: String;
|
|
begin
|
|
Result:=mrCancel;
|
|
if NewSource=nil then begin
|
|
DebugLn(['TMainIDE.DoJumpToCodePosition ERROR: missing NewSource']);
|
|
DumpStack;
|
|
exit;
|
|
end;
|
|
|
|
if ActiveSrcEdit = nil then
|
|
SrcEdit := nil
|
|
else
|
|
SrcEdit := ActiveSrcEdit as TSourceEditor;
|
|
|
|
SourceEditorManager.BeginAutoFocusLock;
|
|
try
|
|
if (SrcEdit=nil) or (ActiveUnitInfo=nil) then
|
|
GetCurrentUnit(SrcEdit,ActiveUnitInfo);
|
|
|
|
if (jfAddJumpPoint in Flags) and (ActiveUnitInfo <> nil) and (SrcEdit <> nil)
|
|
then begin
|
|
if (NewSource<>ActiveUnitInfo.Source)
|
|
or (SrcEdit.EditorComponent.CaretX<>NewX)
|
|
or (SrcEdit.EditorComponent.CaretY<>NewY) then
|
|
SourceEditorManager.AddJumpPointClicked(Self);
|
|
end;
|
|
|
|
if (ActiveUnitInfo = nil) or (NewSource<>ActiveUnitInfo.Source)
|
|
then begin
|
|
// jump to other file -> open it
|
|
ActiveUnitInfo := Project1.UnitInfoWithFilename(NewSource.Filename);
|
|
if (ActiveUnitInfo = nil) and (Project1.IsVirtual) and (jfSearchVirtualFullPath in Flags)
|
|
then begin
|
|
s := AppendPathDelim(GetTestBuildDirectory);
|
|
if LazUTF8.UTF8LowerCase(copy(NewSource.Filename, 1, length(s))) = LazUTF8.UTF8LowerCase(s)
|
|
then ActiveUnitInfo := Project1.UnitInfoWithFilename(copy(NewSource.Filename, 1 + length(s), length(NewSource.Filename)), [pfsfOnlyVirtualFiles]);
|
|
end;
|
|
|
|
|
|
AnEditorInfo := nil;
|
|
if ActiveUnitInfo <> nil then
|
|
AnEditorInfo := GetAvailableUnitEditorInfo(ActiveUnitInfo, Point(NewX,NewY), NewTopLine);
|
|
if AnEditorInfo <> nil then begin
|
|
SourceEditorManager.ActiveEditor := TSourceEditor(AnEditorInfo.EditorComponent);
|
|
Result := mrOK;
|
|
end
|
|
else
|
|
Result:=DoOpenEditorFile(NewSource.Filename,-1,-1,
|
|
[ofOnlyIfExists,ofRegularFile,ofDoNotLoadResource]);
|
|
if Result<>mrOk then begin
|
|
UpdateSourceNames;
|
|
exit;
|
|
end;
|
|
NewSrcEdit := SourceEditorManager.ActiveEditor;
|
|
end
|
|
else begin
|
|
AnEditorInfo := GetAvailableUnitEditorInfo(ActiveUnitInfo, Point(NewX,NewY), NewTopLine);
|
|
if AnEditorInfo <> nil then begin
|
|
NewSrcEdit := TSourceEditor(AnEditorInfo.EditorComponent);
|
|
SourceEditorManager.ActiveEditor := NewSrcEdit;
|
|
end
|
|
else
|
|
NewSrcEdit:=SrcEdit;
|
|
end;
|
|
if NewX<1 then NewX:=1;
|
|
if NewY<1 then NewY:=1;
|
|
if jfMapLineFromDebug in Flags then
|
|
NewY := NewSrcEdit.DebugToSourceLine(NewY);
|
|
//debugln(['[TMainIDE.DoJumpToCodePosition] ',NewX,',',NewY,',',NewTopLine]);
|
|
|
|
try
|
|
NewSrcEdit.BeginUpdate;
|
|
NewSrcEdit.EditorComponent.MoveLogicalCaretIgnoreEOL(Point(NewX,NewY));
|
|
if not NewSrcEdit.IsLocked then begin
|
|
if NewTopLine < 1 then
|
|
NewSrcEdit.CenterCursor(True)
|
|
else
|
|
NewSrcEdit.TopLine:=NewTopLine;
|
|
end;
|
|
//DebugLn('TMainIDE.DoJumpToCodePosition NewY=',dbgs(NewY),' ',dbgs(TopLine),' ',dbgs(NewTopLine));
|
|
NewSrcEdit.CenterCursorHoriz(hcmSoftKeepEOL);
|
|
finally
|
|
NewSrcEdit.EndUpdate;
|
|
end;
|
|
if jfMarkLine in Flags then
|
|
NewSrcEdit.ErrorLine := NewY;
|
|
|
|
if jfFocusEditor in Flags then
|
|
SourceEditorManager.ShowActiveWindowOnTop(True);
|
|
UpdateSourceNames;
|
|
Result:=mrOk;
|
|
finally
|
|
SourceEditorManager.EndAutoFocusLock;
|
|
end;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
procedure TMainIDE.UpdateSourceNames
|
|
Params: none
|
|
|
|
Check every unit in sourceeditor if the source name has changed and updates
|
|
the notebook page names.
|
|
-------------------------------------------------------------------------------}
|
|
procedure TMainIDE.UpdateSourceNames;
|
|
var
|
|
i: integer;
|
|
AnUnitInfo: TUnitInfo;
|
|
SourceName, PageName: string;
|
|
AEditor: TSourceEditor;
|
|
begin
|
|
for i:=0 to SourceEditorManager.SourceEditorCount-1 do begin
|
|
AEditor := SourceEditorManager.SourceEditors[i];
|
|
AnUnitInfo := Project1.UnitWithEditorComponent(AEditor);
|
|
if AnUnitInfo=nil then continue;
|
|
if FilenameIsPascalUnit(AnUnitInfo.Filename) then begin
|
|
SourceName:=CodeToolBoss.GetCachedSourceName(AnUnitInfo.Source);
|
|
if SourceName<>'' then
|
|
AnUnitInfo.ReadUnitNameFromSource(true);
|
|
end else
|
|
SourceName:='';
|
|
PageName:=CreateSrcEditPageName(SourceName, AnUnitInfo.Filename, AEditor);
|
|
AEditor.PageName := PageName;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.NeedSaveSourceEditorChangesToCodeCache(PageIndex: integer
|
|
): boolean;
|
|
begin
|
|
Result := NeedSaveSourceEditorChangesToCodeCache(
|
|
SourceEditorManager.ActiveSourceWindow.FindSourceEditorWithPageIndex(PageIndex));
|
|
end;
|
|
|
|
function TMainIDE.NeedSaveSourceEditorChangesToCodeCache(AEditor: TSourceEditorInterface): boolean;
|
|
// check if any open source needs to be saved to code tools cache
|
|
var
|
|
i: integer;
|
|
|
|
function NeedSave(SaveEditor: TSourceEditorInterface): boolean;
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
AnUnitInfo := Project1.UnitWithEditorComponent(SaveEditor);
|
|
if (AnUnitInfo<>nil) and SaveEditor.NeedsUpdateCodeBuffer then
|
|
Result:=true
|
|
else
|
|
Result:=false;
|
|
end;
|
|
|
|
begin
|
|
Result:=true;
|
|
if AEditor = nil then begin
|
|
for i := 0 to SourceEditorManager.SourceEditorCount - 1 do
|
|
if NeedSave(SourceEditorManager.SourceEditors[i]) then exit;
|
|
end else begin
|
|
if NeedSave(AEditor) then exit;
|
|
end;
|
|
Result:=false;
|
|
end;
|
|
|
|
procedure TMainIDE.ApplyCodeToolChanges;
|
|
begin
|
|
// all changes were handled automatically by events
|
|
// just clear the logs
|
|
CodeToolBoss.SourceCache.ClearAllSourceLogEntries;
|
|
end;
|
|
|
|
procedure TMainIDE.DoJumpToOtherProcedureSection;
|
|
var ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
NewSource: TCodeBuffer;
|
|
NewX, NewY, NewTopLine: integer;
|
|
RevertableJump: boolean;
|
|
LogCaret: TPoint;
|
|
Flags: TJumpToCodePosFlags;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('');
|
|
writeln('[TMainIDE.DoJumpToProcedureSection] ************');
|
|
{$ENDIF}
|
|
LogCaret:=ActiveSrcEdit.EditorComponent.LogicalCaretXY;
|
|
if CodeToolBoss.JumpToMethod(ActiveUnitInfo.Source,
|
|
LogCaret.X,LogCaret.Y,
|
|
NewSource,NewX,NewY,NewTopLine,RevertableJump) then
|
|
begin
|
|
Flags := [jfAddJumpPoint];
|
|
if not RevertableJump then include(Flags, jfFocusEditor);
|
|
DoJumpToCodePosition(ActiveSrcEdit, ActiveUnitInfo,
|
|
NewSource, NewX, NewY, NewTopLine, Flags);
|
|
end else begin
|
|
DoJumpToCodeToolBossError;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.DoJumpToCodeToolBossError;
|
|
var
|
|
ActiveSrcEdit:TSourceEditor;
|
|
ErrorCaret: TPoint;
|
|
OpenFlags: TOpenFlags;
|
|
ErrorFilename: string;
|
|
ErrorTopLine: integer;
|
|
AnUnitInfo: TUnitInfo;
|
|
AnEditorInfo: TUnitEditorInfo;
|
|
begin
|
|
if CodeToolBoss.ErrorMessage='' then begin
|
|
UpdateSourceNames;
|
|
debugln('TMainIDE.DoJumpToCodeToolBossError No errormessage');
|
|
exit;
|
|
end;
|
|
// syntax error -> show error and jump
|
|
// show error in message view
|
|
DoArrangeSourceEditorAndMessageView(false);
|
|
MessagesView.ClearTillLastSeparator;
|
|
MessagesView.AddSeparator;
|
|
if CodeToolBoss.ErrorCode<>nil then begin
|
|
MessagesView.AddMsg(Project1.RemoveProjectPathFromFilename(
|
|
CodeToolBoss.ErrorCode.Filename)
|
|
+'('+IntToStr(CodeToolBoss.ErrorLine)
|
|
+','+IntToStr(CodeToolBoss.ErrorColumn)
|
|
+') Error: '+CodeToolBoss.ErrorMessage,
|
|
Project1.ProjectDirectory,-1);
|
|
end else
|
|
MessagesView.AddMsg(CodeToolBoss.ErrorMessage,Project1.ProjectDirectory,-1);
|
|
MessagesView.SelectedMessageIndex:=MessagesView.MsgCount-1;
|
|
|
|
// jump to error in source editor
|
|
if CodeToolBoss.ErrorCode<>nil then begin
|
|
ErrorCaret:=Point(CodeToolBoss.ErrorColumn,CodeToolBoss.ErrorLine);
|
|
ErrorFilename:=CodeToolBoss.ErrorCode.Filename;
|
|
ErrorTopLine:=CodeToolBoss.ErrorTopLine;
|
|
SourceEditorManager.AddJumpPointClicked(Self);
|
|
OpenFlags:=[ofOnlyIfExists,ofUseCache];
|
|
if CodeToolBoss.ErrorCode.IsVirtual then
|
|
Include(OpenFlags,ofVirtualFile);
|
|
|
|
AnUnitInfo := Project1.UnitInfoWithFilename(ErrorFilename);
|
|
AnEditorInfo := nil;
|
|
ActiveSrcEdit := nil;
|
|
if AnUnitInfo <> nil then
|
|
AnEditorInfo := GetAvailableUnitEditorInfo(AnUnitInfo, ErrorCaret);
|
|
if AnEditorInfo <> nil then begin
|
|
ActiveSrcEdit := TSourceEditor(AnEditorInfo.EditorComponent);
|
|
SourceEditorManager.ActiveEditor := ActiveSrcEdit;
|
|
end else begin
|
|
if DoOpenEditorFile(ErrorFilename,-1,-1,OpenFlags)=mrOk then
|
|
ActiveSrcEdit:=SourceEditorManager.ActiveEditor;
|
|
end;
|
|
if ActiveSrcEdit<> nil then begin
|
|
IDEWindowCreators.ShowForm(MessagesView,true);
|
|
with ActiveSrcEdit.EditorComponent do begin
|
|
LogicalCaretXY:=ErrorCaret;
|
|
if ErrorTopLine>0 then
|
|
TopLine:=ErrorTopLine;
|
|
end;
|
|
SourceEditorManager.ShowActiveWindowOnTop(True);
|
|
SourceEditorManager.ClearErrorLines;
|
|
ActiveSrcEdit.ErrorLine:=ErrorCaret.Y;
|
|
end;
|
|
end;
|
|
UpdateSourceNames;
|
|
end;
|
|
|
|
procedure TMainIDE.DoFindDeclarationAtCursor;
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
begin
|
|
GetCurrentUnit(ActiveSrcEdit,ActiveUnitInfo);
|
|
if ActiveSrcEdit=nil then exit;
|
|
DoFindDeclarationAtCaret(ActiveSrcEdit.EditorComponent.LogicalCaretXY);
|
|
end;
|
|
|
|
procedure TMainIDE.DoFindDeclarationAtCaret(const LogCaretXY: TPoint);
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
NewSource: TCodeBuffer;
|
|
NewX, NewY, NewTopLine: integer;
|
|
FindFlags: TFindSmartFlags;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('');
|
|
writeln('[TMainIDE.DoFindDeclarationAtCaret] ************');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoFindDeclarationAtCaret A');{$ENDIF}
|
|
//DebugLn(['TMainIDE.DoFindDeclarationAtCaret LogCaretXY=',dbgs(LogCaretXY),' SynEdit.Log=',dbgs(ActiveSrcEdit.EditorComponent.LogicalCaretXY),' SynEdit.Caret=',dbgs(ActiveSrcEdit.EditorComponent.CaretXY)]);
|
|
FindFlags := DefaultFindSmartFlags;
|
|
if CodeToolsOpts.SkipForwardDeclarations then
|
|
Include(FindFlags, fsfSkipClassForward);
|
|
if CodeToolBoss.FindDeclaration(ActiveUnitInfo.Source,
|
|
LogCaretXY.X,LogCaretXY.Y,
|
|
NewSource,NewX,NewY,NewTopLine,FindFlags
|
|
)
|
|
then begin
|
|
//debugln(['TMainIDE.DoFindDeclarationAtCaret ',NewSource.Filename,' NewX=',Newx,',y=',NewY,' ',NewTopLine]);
|
|
DoJumpToCodePosition(ActiveSrcEdit, ActiveUnitInfo,
|
|
NewSource, NewX, NewY, NewTopLine, [jfAddJumpPoint, jfFocusEditor]);
|
|
end else begin
|
|
DoJumpToCodeToolBossError;
|
|
end;
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoFindDeclarationAtCaret B');{$ENDIF}
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
function TMainIDE.DoFindRenameIdentifier(Rename: boolean): TModalResult;
|
|
|
|
-------------------------------------------------------------------------------}
|
|
function TMainIDE.DoFindRenameIdentifier(Rename: boolean): TModalResult;
|
|
var
|
|
Options: TFindRenameIdentifierOptions;
|
|
|
|
// TODO: replace Files: TStringsList with a AVL tree
|
|
|
|
function AddExtraFiles(Files: TStrings): TModalResult;
|
|
var
|
|
i: Integer;
|
|
CurFileMask: string;
|
|
FileInfo: TSearchRec;
|
|
CurDirectory: String;
|
|
CurFilename: String;
|
|
begin
|
|
Result:=mrCancel;
|
|
if (Options.ExtraFiles=nil) then begin
|
|
for i:=0 to Options.ExtraFiles.Count-1 do begin
|
|
CurFileMask:=Options.ExtraFiles[i];
|
|
if not GlobalMacroList.SubstituteStr(CurFileMask) then exit;
|
|
if FindFirstUTF8(CurFileMask,faAnyFile,FileInfo)=0
|
|
then begin
|
|
CurDirectory:=AppendPathDelim(ExtractFilePath(CurFileMask));
|
|
if not FilenameIsAbsolute(CurDirectory) then begin
|
|
CurDirectory:=AppendPathDelim(Project1.ProjectDirectory)
|
|
+CurDirectory;
|
|
end;
|
|
repeat
|
|
// check if special file
|
|
if (FileInfo.Name='.') or (FileInfo.Name='..') or (FileInfo.Name='')
|
|
then
|
|
continue;
|
|
CurFilename:=CurDirectory+FileInfo.Name;
|
|
if FileIsText(CurFilename) then
|
|
Files.Add(CurFilename);
|
|
until FindNextUTF8(FileInfo)<>0;
|
|
end;
|
|
FindCloseUTF8(FileInfo);
|
|
end;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
var
|
|
TargetSrcEdit, DeclarationSrcEdit: TSourceEditor;
|
|
TargetUnitInfo, DeclarationUnitInfo: TUnitInfo;
|
|
NewSource: TCodeBuffer;
|
|
NewX, NewY, NewTopLine: integer;
|
|
LogCaretXY, DeclarationCaretXY: TPoint;
|
|
OwnerList: TFPList;
|
|
ExtraFiles: TStrings;
|
|
Files: TStringList;
|
|
Identifier: string;
|
|
PascalReferences: TAVLTree;
|
|
ListOfLazFPDocNode: TFPList;
|
|
CurUnitname: String;
|
|
begin
|
|
Result:=mrCancel;
|
|
if not BeginCodeTool(TargetSrcEdit,TargetUnitInfo,[]) then exit;
|
|
|
|
// find the main declaration
|
|
LogCaretXY:=TargetSrcEdit.EditorComponent.LogicalCaretXY;
|
|
if not CodeToolBoss.FindMainDeclaration(TargetUnitInfo.Source,
|
|
LogCaretXY.X,LogCaretXY.Y,
|
|
NewSource,NewX,NewY,NewTopLine) then
|
|
begin
|
|
DoJumpToCodeToolBossError;
|
|
exit;
|
|
end;
|
|
DoJumpToCodePosition(TargetSrcEdit, TargetUnitInfo,
|
|
NewSource, NewX, NewY, NewTopLine, [jfAddJumpPoint, jfFocusEditor]);
|
|
CodeToolBoss.GetIdentifierAt(NewSource,NewX,NewY,Identifier);
|
|
CurUnitname:=ExtractFileNameOnly(NewSource.Filename);
|
|
|
|
GetCurrentUnit(DeclarationSrcEdit,DeclarationUnitInfo);
|
|
DeclarationCaretXY:=DeclarationSrcEdit.EditorComponent.LogicalCaretXY;
|
|
debugln('TMainIDE.DoFindRenameIdentifier A DeclarationCaretXY=x=',dbgs(DeclarationCaretXY.X),' y=',dbgs(DeclarationCaretXY.Y));
|
|
|
|
// let user choose the search scope
|
|
Result:=ShowFindRenameIdentifierDialog(DeclarationUnitInfo.Source.Filename,
|
|
DeclarationCaretXY,true,Rename,nil);
|
|
if Result<>mrOk then begin
|
|
debugln('TMainIDE.DoFindRenameIdentifier failed: let user choose the search scope');
|
|
exit;
|
|
end;
|
|
|
|
Files:=nil;
|
|
OwnerList:=nil;
|
|
PascalReferences:=nil;
|
|
ListOfLazFPDocNode:=nil;
|
|
try
|
|
// create the file list
|
|
Files:=TStringList.Create;
|
|
Files.Add(TargetUnitInfo.Filename);
|
|
if CompareFilenames(DeclarationUnitInfo.Filename,TargetUnitInfo.Filename)<>0
|
|
then
|
|
Files.Add(DeclarationUnitInfo.Filename);
|
|
|
|
Options:=MiscellaneousOptions.FindRenameIdentifierOptions;
|
|
|
|
// add packages, projects
|
|
case Options.Scope of
|
|
frProject:
|
|
begin
|
|
OwnerList:=TFPList.Create;
|
|
OwnerList.Add(Project1);
|
|
end;
|
|
frOwnerProjectPackage,frAllOpenProjectsAndPackages:
|
|
begin
|
|
OwnerList:=PkgBoss.GetOwnersOfUnit(TargetUnitInfo.Filename);
|
|
if (OwnerList<>nil)
|
|
and (Options.Scope=frAllOpenProjectsAndPackages) then begin
|
|
PkgBoss.ExtendOwnerListWithUsedByOwners(OwnerList);
|
|
ReverseList(OwnerList);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// get source files of packages and projects
|
|
if OwnerList<>nil then begin
|
|
ExtraFiles:=PkgBoss.GetSourceFilesOfOwners(OwnerList);
|
|
try
|
|
if ExtraFiles<>nil then
|
|
Files.AddStrings(ExtraFiles);
|
|
finally
|
|
ExtraFiles.Free;
|
|
end;
|
|
end;
|
|
|
|
// add user defined extra files
|
|
Result:=AddExtraFiles(Files);
|
|
if Result<>mrOk then begin
|
|
debugln('TMainIDE.DoFindRenameIdentifier unable to add user defined extra files');
|
|
exit;
|
|
end;
|
|
|
|
// search pascal source references
|
|
Result:=GatherIdentifierReferences(Files,DeclarationUnitInfo.Source,
|
|
DeclarationCaretXY,Options.SearchInComments,PascalReferences);
|
|
if CodeToolBoss.ErrorMessage<>'' then
|
|
DoJumpToCodeToolBossError;
|
|
if Result<>mrOk then begin
|
|
debugln('TMainIDE.DoFindRenameIdentifier GatherIdentifierReferences failed');
|
|
exit;
|
|
end;
|
|
|
|
{$IFDEF EnableFPDocRename}
|
|
// search fpdoc references
|
|
Result:=GatherFPDocReferencesForPascalFiles(Files,DeclarationUnitInfo.Source,
|
|
DeclarationCaretXY,ListOfLazFPDocNode);
|
|
if Result<>mrOk then begin
|
|
debugln('TMainIDE.DoFindRenameIdentifier GatherFPDocReferences failed');
|
|
exit;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
// ToDo: search lfm source references
|
|
// ToDo: search i18n references
|
|
// ToDo: designer references
|
|
|
|
// rename identifier
|
|
if Options.Rename then begin
|
|
if CompareIdentifiers(PChar(Identifier),PChar(CurUnitName))=0 then
|
|
begin
|
|
IDEMessageDialog(srkmecRenameIdentifier,
|
|
lisTheIdentifierIsAUnitPleaseUseTheFileSaveAsFunction,
|
|
mtInformation,[mbCancel],'');
|
|
exit(mrCancel);
|
|
end;
|
|
if not CodeToolBoss.RenameIdentifier(PascalReferences,
|
|
Identifier,Options.RenameTo)
|
|
then begin
|
|
DoJumpToCodeToolBossError;
|
|
debugln('TMainIDE.DoFindRenameIdentifier unable to commit');
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
// show result
|
|
if (not Options.Rename) or (not Rename) then begin
|
|
Result:=ShowIdentifierReferences(DeclarationUnitInfo.Source,
|
|
DeclarationCaretXY,PascalReferences);
|
|
if Result<>mrOk then exit;
|
|
end;
|
|
|
|
finally
|
|
Files.Free;
|
|
OwnerList.Free;
|
|
CodeToolBoss.FreeTreeOfPCodeXYPosition(PascalReferences);
|
|
FreeListObjects(ListOfLazFPDocNode,true);
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoShowAbstractMethods: TModalResult;
|
|
begin
|
|
Result:=ShowAbstractMethodsDialog;
|
|
end;
|
|
|
|
function TMainIDE.DoRemoveEmptyMethods: TModalResult;
|
|
begin
|
|
Result:=ShowEmptyMethodsDialog;
|
|
end;
|
|
|
|
function TMainIDE.DoRemoveUnusedUnits: TModalResult;
|
|
begin
|
|
Result:=ShowUnusedUnitsDialog;
|
|
end;
|
|
|
|
function TMainIDE.DoUseUnit: TModalResult;
|
|
begin
|
|
Result:=ShowUseUnitDialog;
|
|
end;
|
|
|
|
function TMainIDE.DoFindOverloads: TModalResult;
|
|
begin
|
|
Result:=ShowFindOverloadsDialog;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
function TMainIDE.DoInitIdentCompletion(JumpToError: boolean): boolean;
|
|
-------------------------------------------------------------------------------}
|
|
function TMainIDE.DoInitIdentCompletion(JumpToError: boolean): boolean;
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
LogCaretXY: TPoint;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit(false);
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('');
|
|
writeln('[TMainIDE.DoInitIdentCompletion] ************');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoInitIdentCompletion A');{$ENDIF}
|
|
LogCaretXY:=ActiveSrcEdit.EditorComponent.LogicalCaretXY;
|
|
Result:=CodeToolBoss.GatherIdentifiers(ActiveUnitInfo.Source,
|
|
LogCaretXY.X,LogCaretXY.Y);
|
|
if not Result then begin
|
|
if JumpToError then
|
|
DoJumpToCodeToolBossError;
|
|
exit;
|
|
end;
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoInitIdentCompletion B');{$ENDIF}
|
|
end;
|
|
|
|
function TMainIDE.DoShowCodeContext(JumpToError: boolean): boolean;
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit(false);
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('');
|
|
writeln('[TMainIDE.DoShowCodeContext] ************');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoShowCodeContext A');{$ENDIF}
|
|
Result:=ShowCodeContext(ActiveUnitInfo.Source);
|
|
if not Result then begin
|
|
if JumpToError then
|
|
DoJumpToCodeToolBossError;
|
|
exit;
|
|
end;
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.DoShowCodeContext B');{$ENDIF}
|
|
end;
|
|
|
|
procedure TMainIDE.DoGoToPascalBlockOtherEnd;
|
|
var ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
NewSource: TCodeBuffer;
|
|
NewX, NewY, NewTopLine: integer;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('');
|
|
writeln('[TMainIDE.DoGoToPascalBlockOtherEnd] ************');
|
|
{$ENDIF}
|
|
if CodeToolBoss.FindBlockCounterPart(ActiveUnitInfo.Source,
|
|
ActiveSrcEdit.EditorComponent.CaretX,
|
|
ActiveSrcEdit.EditorComponent.CaretY,
|
|
NewSource,NewX,NewY,NewTopLine) then
|
|
begin
|
|
DoJumpToCodePosition(ActiveSrcEdit, ActiveUnitInfo,
|
|
NewSource, NewX, NewY, NewTopLine, [jfFocusEditor]);
|
|
end else
|
|
DoJumpToCodeToolBossError;
|
|
end;
|
|
|
|
procedure TMainIDE.DoGoToPascalBlockStart;
|
|
var ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
NewSource: TCodeBuffer;
|
|
NewX, NewY, NewTopLine: integer;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('');
|
|
writeln('[TMainIDE.DoGoToPascalBlockStart] ************');
|
|
{$ENDIF}
|
|
if CodeToolBoss.FindBlockStart(ActiveUnitInfo.Source,
|
|
ActiveSrcEdit.EditorComponent.CaretX,
|
|
ActiveSrcEdit.EditorComponent.CaretY,
|
|
NewSource,NewX,NewY,NewTopLine) then
|
|
begin
|
|
DoJumpToCodePosition(ActiveSrcEdit, ActiveUnitInfo,
|
|
NewSource, NewX, NewY, NewTopLine, [jfFocusEditor]);
|
|
end else
|
|
DoJumpToCodeToolBossError;
|
|
end;
|
|
|
|
procedure TMainIDE.DoJumpToGuessedUnclosedBlock(FindNextUTF8: boolean);
|
|
var ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
NewSource: TCodeBuffer;
|
|
StartX, StartY, NewX, NewY, NewTopLine: integer;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('');
|
|
writeln('[TMainIDE.DoJumpToGuessedUnclosedBlock] ************');
|
|
{$ENDIF}
|
|
if FindNextUTF8 then begin
|
|
StartX:=ActiveSrcEdit.EditorComponent.CaretX;
|
|
StartY:=ActiveSrcEdit.EditorComponent.CaretY;
|
|
end else begin
|
|
StartX:=1;
|
|
StartY:=1;
|
|
end;
|
|
if CodeToolBoss.GuessUnclosedBlock(ActiveUnitInfo.Source,
|
|
StartX,StartY,NewSource,NewX,NewY,NewTopLine) then
|
|
begin
|
|
DoJumpToCodePosition(ActiveSrcEdit, ActiveUnitInfo,
|
|
NewSource, NewX, NewY, NewTopLine, [jfAddJumpPoint, jfFocusEditor]);
|
|
end else begin
|
|
if CodeToolBoss.ErrorMessage='' then begin
|
|
MessageDlg(lisSuccess, lisAllBlocksLooksOk, mtInformation, [mbOk], 0);
|
|
end else
|
|
DoJumpToCodeToolBossError;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.DoJumpToGuessedMisplacedIFDEF(FindNextUTF8: boolean);
|
|
var ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
NewSource: TCodeBuffer;
|
|
StartX, StartY, NewX, NewY, NewTopLine: integer;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('');
|
|
writeln('[TMainIDE.DoJumpToGuessedMisplacedIFDEF] ************');
|
|
{$ENDIF}
|
|
if FindNextUTF8 then begin
|
|
StartX:=ActiveSrcEdit.EditorComponent.CaretX;
|
|
StartY:=ActiveSrcEdit.EditorComponent.CaretY;
|
|
end else begin
|
|
StartX:=1;
|
|
StartY:=1;
|
|
end;
|
|
if CodeToolBoss.GuessMisplacedIfdefEndif(ActiveUnitInfo.Source,
|
|
StartX,StartY,NewSource,NewX,NewY,NewTopLine) then
|
|
begin
|
|
DoJumpToCodePosition(ActiveSrcEdit, ActiveUnitInfo,
|
|
NewSource, NewX, NewY, NewTopLine, [jfAddJumpPoint, jfFocusEditor]);
|
|
end else
|
|
DoJumpToCodeToolBossError;
|
|
end;
|
|
|
|
procedure TMainIDE.DoGotoIncludeDirective;
|
|
var ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
NewSource: TCodeBuffer;
|
|
NewX, NewY, NewTopLine: integer;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('');
|
|
writeln('[TMainIDE.DoGotoIncludeDirective] ************');
|
|
{$ENDIF}
|
|
if CodeToolBoss.FindEnclosingIncludeDirective(ActiveUnitInfo.Source,
|
|
ActiveSrcEdit.EditorComponent.CaretX,
|
|
ActiveSrcEdit.EditorComponent.CaretY,
|
|
NewSource,NewX,NewY,NewTopLine) then
|
|
begin
|
|
DoJumpToCodePosition(ActiveSrcEdit, ActiveUnitInfo,
|
|
NewSource, NewX, NewY, NewTopLine, [jfFocusEditor]);
|
|
end else
|
|
DoJumpToCodeToolBossError;
|
|
end;
|
|
|
|
procedure TMainIDE.SaveIncludeLinks;
|
|
var AFilename: string;
|
|
begin
|
|
// save include file relationships
|
|
AFilename:=AppendPathDelim(GetPrimaryConfigPath)+CodeToolsIncludeLinkFile;
|
|
CodeToolBoss.SourceCache.SaveIncludeLinksToFile(AFilename,true);
|
|
end;
|
|
|
|
function TMainIDE.DoMakeResourceString: TModalResult;
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
StartPos, EndPos: TPoint;
|
|
StartCode, EndCode: TCodeBuffer;
|
|
NewIdentifier, NewIdentValue: string;
|
|
NewSourceLines: string;
|
|
InsertPolicy: TResourcestringInsertPolicy;
|
|
SectionCode: TCodeBuffer;
|
|
SectionCaretXY: TPoint;
|
|
DummyResult: Boolean;
|
|
SelectedStartPos: TPoint;
|
|
SelectedEndPos: TPoint;
|
|
CursorCode: TCodeBuffer;
|
|
CursorXY: TPoint;
|
|
OldChange: Boolean;
|
|
begin
|
|
OldChange:=OpenEditorsOnCodeToolChange;
|
|
OpenEditorsOnCodeToolChange:=true;
|
|
try
|
|
Result:=mrCancel;
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
debugln('');
|
|
debugln('[TMainIDE.DoMakeResourceString] ************');
|
|
{$ENDIF}
|
|
// calculate start and end of expression in source
|
|
CursorCode:=ActiveUnitInfo.Source;
|
|
if ActiveSrcEdit.EditorComponent.SelAvail then
|
|
CursorXY:=ActiveSrcEdit.EditorComponent.BlockBegin
|
|
else
|
|
CursorXY:=ActiveSrcEdit.EditorComponent.LogicalCaretXY;
|
|
if not CodeToolBoss.GetStringConstBounds(
|
|
CursorCode,CursorXY.X,CursorXY.Y,
|
|
StartCode,StartPos.X,StartPos.Y,
|
|
EndCode,EndPos.X,EndPos.Y,true) then
|
|
begin
|
|
DoJumpToCodeToolBossError;
|
|
exit;
|
|
end;
|
|
|
|
// the codetools have calculated the maximum bounds
|
|
if (StartCode=EndCode) and (CompareCaret(StartPos,EndPos)=0) then begin
|
|
MessageDlg(lisNoStringConstantFound,
|
|
Format(lisHintTheMakeResourcestringFunctionExpectsAStringCon, [#13]),
|
|
mtError,[mbCancel],0);
|
|
exit;
|
|
end;
|
|
// the user can shorten this range by selecting text
|
|
if (ActiveSrcEdit.EditorComponent.SelText='') then begin
|
|
// the user has not selected text
|
|
// -> check if the string constant is in single file
|
|
// (replacing code that contains an $include directive is ambiguous)
|
|
//debugln('TMainIDE.DoMakeResourceString user has not selected text');
|
|
if (StartCode<>ActiveUnitInfo.Source)
|
|
or (EndCode<>ActiveUnitInfo.Source)
|
|
then begin
|
|
MessageDlg(lisNoStringConstantFound, Format(
|
|
lisInvalidExpressionHintTheMakeResourcestringFunction, [#13]),
|
|
mtError,[mbCancel],0);
|
|
exit;
|
|
end;
|
|
end else begin
|
|
// the user has selected text
|
|
// -> check if the selection is only part of the maximum bounds
|
|
SelectedStartPos:=ActiveSrcEdit.EditorComponent.BlockBegin;
|
|
SelectedEndPos:=ActiveSrcEdit.EditorComponent.BlockEnd;
|
|
CodeToolBoss.ImproveStringConstantStart(
|
|
ActiveSrcEdit.EditorComponent.Lines[SelectedStartPos.Y-1],
|
|
SelectedStartPos.X);
|
|
CodeToolBoss.ImproveStringConstantEnd(
|
|
ActiveSrcEdit.EditorComponent.Lines[SelectedEndPos.Y-1],
|
|
SelectedEndPos.X);
|
|
//debugln('TMainIDE.DoMakeResourceString user has selected text: Selected=',dbgs(SelectedStartPos),'-',dbgs(SelectedEndPos),' Maximum=',dbgs(StartPos),'-',dbgs(EndPos));
|
|
if (CompareCaret(SelectedStartPos,StartPos)>0)
|
|
or (CompareCaret(SelectedEndPos,EndPos)<0)
|
|
then begin
|
|
MessageDlg(lisSelectionExceedsStringConstant,
|
|
Format(lisHintTheMakeResourcestringFunctionExpectsAStringCon2, [#13]),
|
|
mtError,[mbCancel],0);
|
|
exit;
|
|
end;
|
|
StartPos:=SelectedStartPos;
|
|
EndPos:=SelectedEndPos;
|
|
end;
|
|
|
|
// gather all reachable resourcestring sections
|
|
//debugln('TMainIDE.DoMakeResourceString gather all reachable resourcestring sections ...');
|
|
if not CodeToolBoss.GatherResourceStringSections(
|
|
CursorCode,CursorXY.X,CursorXY.Y,nil)
|
|
then begin
|
|
DoJumpToCodeToolBossError;
|
|
exit;
|
|
end;
|
|
if CodeToolBoss.Positions.Count=0 then begin
|
|
MessageDlg(lisNoResourceStringSectionFound,
|
|
lisUnableToFindAResourceStringSectionInThisOrAnyOfThe,
|
|
mtError,[mbCancel],0);
|
|
exit;
|
|
end;
|
|
|
|
// show make resourcestring dialog
|
|
Result:=ShowMakeResStrDialog(StartPos,EndPos,StartCode,
|
|
CodeToolBoss.Positions,
|
|
NewIdentifier,NewIdentValue,NewSourceLines,
|
|
SectionCode,SectionCaretXY,InsertPolicy);
|
|
if (Result<>mrOk) then exit;
|
|
|
|
// replace source
|
|
ActiveSrcEdit.ReplaceLines(StartPos.Y,EndPos.Y,NewSourceLines);
|
|
|
|
// add new resourcestring to resourcestring section
|
|
if (InsertPolicy<>rsipNone) then
|
|
DummyResult:=CodeToolBoss.AddResourcestring(
|
|
CursorCode,CursorXY.X,CursorXY.Y,
|
|
SectionCode,SectionCaretXY.X,SectionCaretXY.Y,
|
|
NewIdentifier,''''+NewIdentValue+'''',InsertPolicy)
|
|
else
|
|
DummyResult:=true;
|
|
ApplyCodeToolChanges;
|
|
if not DummyResult then begin
|
|
DoJumpToCodeToolBossError;
|
|
exit;
|
|
end;
|
|
|
|
// switch back to source
|
|
ActiveSrcEdit.Activate;
|
|
|
|
Result:=mrOk;
|
|
finally
|
|
OpenEditorsOnCodeToolChange:=OldChange;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoDiff: TModalResult;
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
OpenDiffInEditor: boolean;
|
|
DiffText: string;
|
|
NewDiffFilename: String;
|
|
begin
|
|
Result:=mrCancel;
|
|
GetCurrentUnit(ActiveSrcEdit,ActiveUnitInfo);
|
|
if ActiveSrcEdit=nil then exit;
|
|
|
|
Result:=ShowDiffDialog(ActiveSrcEdit.PageIndex,
|
|
OpenDiffInEditor,DiffText);
|
|
if OpenDiffInEditor then begin
|
|
NewDiffFilename:=CreateSrcEditPageName('','diff.txt', nil);
|
|
Result:=DoNewEditorFile(FileDescriptorText,NewDiffFilename,DiffText,
|
|
[nfOpenInEditor]);
|
|
GetCurrentUnit(ActiveSrcEdit,ActiveUnitInfo);
|
|
if ActiveSrcEdit=nil then exit;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoFindInFiles: TModalResult;
|
|
begin
|
|
Result:=mrOk;
|
|
FindInFilesDialog.FindInFilesPerDialog(Project1);
|
|
end;
|
|
|
|
procedure TMainIDE.DoCompleteCodeAtCursor;
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
NewSource: TCodeBuffer;
|
|
NewX, NewY, NewTopLine: integer;
|
|
OldChange: Boolean;
|
|
begin
|
|
OldChange:=OpenEditorsOnCodeToolChange;
|
|
OpenEditorsOnCodeToolChange:=true;
|
|
try
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('');
|
|
writeln('[TMainIDE.DoCompleteCodeAtCursor] ************');
|
|
{$ENDIF}
|
|
if CodeToolBoss.CompleteCode(ActiveUnitInfo.Source,
|
|
ActiveSrcEdit.EditorComponent.CaretX,
|
|
ActiveSrcEdit.EditorComponent.CaretY,
|
|
ActiveSrcEdit.EditorComponent.TopLine,
|
|
NewSource,NewX,NewY,NewTopLine) then
|
|
begin
|
|
ApplyCodeToolChanges;
|
|
if NewSource<>nil then
|
|
DoJumpToCodePosition(ActiveSrcEdit, ActiveUnitInfo,
|
|
NewSource, NewX, NewY, NewTopLine, [jfAddJumpPoint, jfFocusEditor]);
|
|
end else begin
|
|
// error: probably a syntax error or just not in a procedure head/body
|
|
// or not in a class
|
|
// -> there are enough events to handle everything, so it can be ignored here
|
|
ApplyCodeToolChanges;
|
|
DoJumpToCodeToolBossError;
|
|
end;
|
|
finally
|
|
OpenEditorsOnCodeToolChange:=OldChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.DoExtractProcFromSelection;
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
BlockBegin: TPoint;
|
|
BlockEnd: TPoint;
|
|
NewSource: TCodeBuffer;
|
|
NewX, NewY, NewTopLine: integer;
|
|
CTResult: boolean;
|
|
OldChange: Boolean;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('');
|
|
writeln('[TMainIDE.DoExtractProcFromSelection] ************');
|
|
{$ENDIF}
|
|
BlockBegin:=ActiveSrcEdit.EditorComponent.BlockBegin;
|
|
BlockEnd:=ActiveSrcEdit.EditorComponent.BlockEnd;
|
|
|
|
OldChange:=OpenEditorsOnCodeToolChange;
|
|
OpenEditorsOnCodeToolChange:=true;
|
|
try
|
|
CTResult:=ShowExtractProcDialog(ActiveUnitInfo.Source,BlockBegin,BlockEnd,
|
|
NewSource,NewX,NewY,NewTopLine)=mrOk;
|
|
ApplyCodeToolChanges;
|
|
if CodeToolBoss.ErrorMessage<>'' then begin
|
|
DoJumpToCodeToolBossError;
|
|
end else if CTResult then begin
|
|
DoJumpToCodePosition(ActiveSrcEdit,ActiveUnitInfo,
|
|
NewSource,NewX,NewY,NewTopLine,[jfAddJumpPoint, jfFocusEditor]);
|
|
end;
|
|
finally
|
|
OpenEditorsOnCodeToolChange:=OldChange;
|
|
end;
|
|
end;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
procedure TMainIDE.MessagesViewSelectionChanged(sender: TObject);
|
|
begin
|
|
DoJumpToCompilerMessage(TMessagesView(Sender).SelectedMessageIndex,True);
|
|
end;
|
|
|
|
procedure TMainIDE.SearchResultsViewSelectionChanged(sender: TObject);
|
|
begin
|
|
DoJumpToSearchResult(True);
|
|
end;
|
|
|
|
procedure TMainIDE.JumpHistoryViewSelectionChanged(sender : TObject);
|
|
begin
|
|
SourceEditorManager.HistoryJump(self, jhaViewWindow);
|
|
SourceEditorManager.ShowActiveWindowOnTop(True);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookEditorActived(Sender: TObject);
|
|
var
|
|
ActiveUnitInfo: TUnitInfo;
|
|
ASrcEdit: TSourceEditor;
|
|
begin
|
|
if SourceEditorManager.SourceEditorCount = 0 then Exit;
|
|
ASrcEdit := TSourceEditor(Sender);
|
|
|
|
if Sender <> nil then
|
|
Project1.UpdateVisibleUnit(ASrcEdit,
|
|
SourceEditorManager.IndexOfSourceWindow(ASrcEdit.SourceNotebook));
|
|
|
|
ActiveUnitInfo :=
|
|
Project1.UnitWithEditorComponent(SourceEditorManager.ActiveEditor);
|
|
if ActiveUnitInfo = nil then Exit;
|
|
ActiveUnitInfo.SetLastUsedEditor(SourceEditorManager.ActiveEditor);
|
|
|
|
UpdateSaveMenuItemsAndButtons(false);
|
|
MainIDEBar.itmViewToggleFormUnit.Enabled := Assigned(ActiveUnitInfo.Component)
|
|
or (ActiveUnitInfo.ComponentName<>'');
|
|
MainIDEBar.ToggleFormSpeedBtn.Enabled := MainIDEBar.itmViewToggleFormUnit.Enabled;
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookEditorPlaceBookmark(Sender: TObject;
|
|
var Mark: TSynEditMark);
|
|
begin
|
|
Project1.UnitWithEditorComponent(TSourceEditor(Sender)).AddBookmark
|
|
(Mark.Column, Mark.Line, Mark.BookmarkNumber);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookEditorClearBookmark(Sender: TObject;
|
|
var Mark: TSynEditMark);
|
|
begin
|
|
Project1.UnitWithEditorComponent(TSourceEditor(Sender)).DeleteBookmark
|
|
(Mark.BookmarkNumber);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookEditorDoSetBookmark(Sender: TObject; ID: Integer; Toggle: Boolean);
|
|
var
|
|
ActEdit, OldEdit: TSourceEditor;
|
|
Cmd: TIDEMenuCommand;
|
|
OldX, OldY: integer;
|
|
NewXY: TPoint;
|
|
SetMark: Boolean;
|
|
AnUnitInfo: TUnitInfo;
|
|
Begin
|
|
if ID < 0 then begin
|
|
ID := 0;
|
|
while (ID <= 9) and (Project1.Bookmarks.BookmarkWithID(ID) <> nil) do
|
|
inc(ID);
|
|
if ID > 9 then exit;
|
|
end;
|
|
ActEdit := Sender as TSourceEditor;
|
|
NewXY := ActEdit.EditorComponent.CaretXY;
|
|
|
|
SetMark:=true;
|
|
OldEdit := nil;
|
|
AnUnitInfo := TUnitInfo(Project1.Bookmarks.UnitInfoForBookmarkWithIndex(ID));
|
|
if (AnUnitInfo <> nil) and (AnUnitInfo.OpenEditorInfoCount > 0) then
|
|
OldEdit := TSourceEditor(AnUnitInfo.OpenEditorInfo[0].EditorComponent);
|
|
if (OldEdit<>nil) and OldEdit.EditorComponent.GetBookMark(ID,OldX,OldY) then
|
|
begin
|
|
if (not Toggle) and (OldX=NewXY.X) and (OldY=NewXY.Y) then
|
|
exit; // no change
|
|
OldEdit.EditorComponent.ClearBookMark(ID);
|
|
if Toggle and (OldY=NewXY.Y) then
|
|
SetMark:=false;
|
|
end;
|
|
if SetMark then
|
|
ActEdit.EditorComponent.SetBookMark(ID,NewXY.X,NewXY.Y);
|
|
Cmd:=SrcEditSubMenuToggleBookmarks[ID] as TIDEMenuCommand;
|
|
Cmd.Checked := SetMark;
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookEditorDoGotoBookmark(Sender: TObject; ID: Integer; Backward: Boolean);
|
|
var
|
|
CurWin, CurPage, CurLine: Integer;
|
|
|
|
function GetWinForEdit(AEd: TSourceEditor): Integer;
|
|
begin
|
|
Result := SourceEditorManager.IndexOfSourceWindow(AEd.SourceNotebook);
|
|
if (not Backward) and
|
|
( (Result < CurWin) or ((Result = CurWin) and (AEd.PageIndex < CurPage)) )
|
|
then inc(Result, SourceEditorManager.SourceWindowCount);
|
|
if (Backward) and
|
|
( (Result > CurWin) or ((Result = CurWin) and (AEd.PageIndex > CurPage)) )
|
|
then dec(Result, SourceEditorManager.SourceWindowCount);
|
|
end;
|
|
|
|
function GetSrcEdit(AMark: TProjectBookmark): TSourceEditor;
|
|
var
|
|
UInf: TUnitInfo;
|
|
i, j: Integer;
|
|
begin
|
|
if AMark.UnitInfo is TSourceEditor
|
|
then Result := TSourceEditor(AMark.UnitInfo)
|
|
else begin // find the nearest open View
|
|
UInf := TUnitInfo(AMark.UnitInfo);
|
|
Result := TSourceEditor(UInf.OpenEditorInfo[0].EditorComponent);
|
|
j := 0;
|
|
while (j < UInf.OpenEditorInfoCount) and
|
|
(Result.IsLocked) and (not Result.IsCaretOnScreen(AMark.CursorPos))
|
|
do begin
|
|
inc(j);
|
|
if j < UInf.OpenEditorInfoCount then
|
|
Result := TSourceEditor(UInf.OpenEditorInfo[j].EditorComponent);
|
|
end;
|
|
if j >= UInf.OpenEditorInfoCount then
|
|
exit(nil);
|
|
for i := j + 1 to UInf.OpenEditorInfoCount - 1 do
|
|
begin
|
|
if (not Backward) and
|
|
(GetWinForEdit(Result) > GetWinForEdit(TSourceEditor(UInf.OpenEditorInfo[i].EditorComponent)) )
|
|
then Result := TSourceEditor(UInf.OpenEditorInfo[i].EditorComponent);
|
|
if (Backward) and
|
|
(GetWinForEdit(Result) < GetWinForEdit(TSourceEditor(UInf.OpenEditorInfo[i].EditorComponent)) )
|
|
then Result := TSourceEditor(UInf.OpenEditorInfo[i].EditorComponent);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function GetWin(AMark: TProjectBookmark): Integer;
|
|
var
|
|
Ed: TSourceEditor;
|
|
begin
|
|
Ed := GetSrcEdit(AMark);
|
|
Result := SourceEditorManager.IndexOfSourceWindow(Ed.SourceNotebook);
|
|
if (not Backward) and (
|
|
(Result < CurWin) or
|
|
((Result = CurWin) and (Ed.PageIndex < CurPage)) or
|
|
((Result = CurWin) and (Ed.PageIndex = CurPage) and (AMark.CursorPos.y < CurLine))
|
|
)
|
|
then
|
|
inc(Result, SourceEditorManager.SourceWindowCount);
|
|
if (Backward) and (
|
|
(Result > CurWin) or
|
|
((Result = CurWin) and (Ed.PageIndex > CurPage)) or
|
|
((Result = CurWin) and (Ed.PageIndex = CurPage) and (AMark.CursorPos.y > CurLine))
|
|
)
|
|
then
|
|
dec(Result, SourceEditorManager.SourceWindowCount);
|
|
end;
|
|
|
|
function CompareBookmarkEditorPos(Mark1, Mark2: TProjectBookmark): integer;
|
|
begin
|
|
// ProjectMarks, only exist for UnitInfo with at least one Editor
|
|
Result := GetWin(Mark2) - GetWin(Mark1);
|
|
if Result = 0 then
|
|
Result := GetSrcEdit(Mark2).PageIndex - GetSrcEdit(Mark1).PageIndex;
|
|
if Result = 0 then
|
|
Result := Mark2.CursorPos.y - Mark1.CursorPos.y;
|
|
end;
|
|
|
|
var
|
|
AnEditor: TSourceEditor;
|
|
i: Integer;
|
|
CurPos, CurFound: TProjectBookmark;
|
|
AnUnitInfo: TUnitInfo;
|
|
AnEditorInfo: TUnitEditorInfo;
|
|
begin
|
|
if ID < 0 then begin
|
|
// ID < 0 => next/prev
|
|
if Project1.BookMarks.Count = 0 then exit;
|
|
AnEditor := SourceEditorManager.ActiveEditor;
|
|
if AnEditor = nil then exit;
|
|
|
|
CurWin := SourceEditorManager.IndexOfSourceWindow(AnEditor.SourceNotebook);
|
|
CurPage := AnEditor.PageIndex;
|
|
CurLine := AnEditor.EditorComponent.CaretY;
|
|
|
|
CurPos := TProjectBookmark.Create(1, CurLine, -1, AnEditor);
|
|
try
|
|
CurFound := nil;
|
|
i := 0;
|
|
while (i < Project1.Bookmarks.Count) and
|
|
( (GetSrcEdit(Project1.Bookmarks[i]) = nil) or
|
|
(CompareBookmarkEditorPos(CurPos, Project1.Bookmarks[i]) = 0) )
|
|
do
|
|
inc(i);
|
|
if i >= Project1.Bookmarks.Count then
|
|
exit; // all on the same line
|
|
|
|
CurFound := Project1.Bookmarks[i];
|
|
inc(i);
|
|
while (i < Project1.Bookmarks.Count) do begin
|
|
if (GetSrcEdit(Project1.Bookmarks[i]) <> nil) then begin
|
|
if (CompareBookmarkEditorPos(CurPos, Project1.Bookmarks[i]) <> 0) then begin
|
|
if (not Backward) and
|
|
(CompareBookmarkEditorPos(Project1.Bookmarks[i], CurFound) > 0)
|
|
then
|
|
CurFound := Project1.Bookmarks[i];
|
|
if (Backward) and
|
|
(CompareBookmarkEditorPos(Project1.Bookmarks[i], CurFound) < 0)
|
|
then
|
|
CurFound := Project1.Bookmarks[i];
|
|
end;
|
|
end;
|
|
inc(i);
|
|
end;
|
|
|
|
if CurFound = nil then exit;
|
|
ID := CurFound.ID;
|
|
finally
|
|
CurPos.Free;
|
|
end;
|
|
|
|
AnEditor := GetSrcEdit(CurFound);
|
|
end
|
|
else begin
|
|
AnEditor := nil;
|
|
AnUnitInfo := TUnitInfo(Project1.Bookmarks.UnitInfoForBookmarkWithIndex(ID));
|
|
AnEditorInfo := nil;
|
|
if (AnUnitInfo <> nil) and (AnUnitInfo.OpenEditorInfoCount > 0) then
|
|
AnEditorInfo := GetAvailableUnitEditorInfo(AnUnitInfo,
|
|
Project1.Bookmarks.BookmarkWithID(ID).CursorPos);
|
|
if AnEditorInfo <> nil then
|
|
AnEditor := TSourceEditor(AnEditorInfo.EditorComponent);
|
|
if AnEditor = nil then exit;
|
|
end;
|
|
|
|
SourceEditorManager.ActiveEditor := AnEditor;
|
|
SourceEditorManager.ShowActiveWindowOnTop(True);
|
|
try
|
|
AnEditor.BeginUpdate;
|
|
AnEditor.EditorComponent.GotoBookMark(ID);
|
|
if not AnEditor.IsLocked then
|
|
AnEditor.CenterCursor(True);
|
|
finally
|
|
AnEditor.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
//this is fired when the editor is focused, changed, ?. Anything that causes the status change
|
|
procedure TMainIDE.OnSrcNotebookEditorChanged(Sender: TObject);
|
|
begin
|
|
if SourceEditorManager.SourceEditorCount = 0 then Exit;
|
|
UpdateSaveMenuItemsAndButtons(false);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookEditorMoved(Sender: TObject);
|
|
var
|
|
p: TUnitEditorInfo;
|
|
i: Integer;
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
SrcEdit := TSourceEditor(Sender);
|
|
p :=Project1.EditorInfoWithEditorComponent(SrcEdit);
|
|
if p <> nil then begin
|
|
p.PageIndex := SrcEdit.PageIndex;
|
|
p.WindowIndex := SourceEditorManager.IndexOfSourceWindow(SrcEdit.SourceNotebook);
|
|
p.IsLocked := SrcEdit.IsLocked;
|
|
end
|
|
else if SrcEdit.IsNewSharedEditor then begin
|
|
// attach to UnitInfo
|
|
SrcEdit.IsNewSharedEditor := False;
|
|
i := 0;
|
|
while (i < SrcEdit.SharedEditorCount) and (SrcEdit.SharedEditors[i] = SrcEdit) do
|
|
inc(i);
|
|
p := Project1.EditorInfoWithEditorComponent(SrcEdit.SharedEditors[i]);
|
|
p := p.UnitInfo.GetClosedOrNewEditorInfo;
|
|
p.EditorComponent := SrcEdit;
|
|
p.SyntaxHighlighter := SrcEdit.SyntaxHighlighterType;
|
|
p.CustomHighlighter := p.SyntaxHighlighter <> p.UnitInfo.DefaultSyntaxHighlighter;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookEditorClosed(Sender: TObject);
|
|
var
|
|
SrcEditor: TSourceEditor;
|
|
p: TUnitEditorInfo;
|
|
begin
|
|
SrcEditor := TSourceEditor(Sender);
|
|
p :=Project1.EditorInfoWithEditorComponent(SrcEditor);
|
|
if (p <> nil) then
|
|
p.EditorComponent := nil // Set EditorIndex := -1
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookCurCodeBufferChanged(Sender: TObject);
|
|
begin
|
|
if SourceEditorManager.SourceEditorCount = 0 then Exit;
|
|
if CodeExplorerView<>nil then CodeExplorerView.CurrentCodeBufferChanged;
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookShowHintForSource(SrcEdit: TSourceEditor;
|
|
ClientPos: TPoint; CaretPos: TPoint);
|
|
var
|
|
ActiveUnitInfo: TUnitInfo;
|
|
BaseURL, SmartHintStr, Expression, DebugEval, DebugEvalDerefer: String;
|
|
DBGType,DBGTypeDerefer: TDBGType;
|
|
HasHint: Boolean;
|
|
p: SizeInt;
|
|
Opts: TDBGEvaluateFlags;
|
|
begin
|
|
//DebugLn(['TMainIDE.OnSrcNotebookShowHintForSource START']);
|
|
if (SrcEdit=nil) then exit;
|
|
|
|
if not BeginCodeTool(SrcEdit, ActiveUnitInfo,
|
|
[ctfUseGivenSourceEditor {, ctfActivateAbortMode}]) then exit;
|
|
|
|
|
|
BaseURL:='';
|
|
SmartHintStr := '';
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('');
|
|
writeln('[TMainIDE.OnSrcNotebookShowHintForSource] ************ ',ActiveUnitInfo.Source.Filename,' X=',CaretPos.X,' Y=',CaretPos.Y);
|
|
{$ENDIF}
|
|
HasHint:=false;
|
|
if EditorOpts.AutoToolTipSymbTools then begin
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.OnSrcNotebookShowHintForSource A');{$ENDIF}
|
|
if TIDEHelpManager(HelpBoss).GetHintForSourcePosition(ActiveUnitInfo.Filename,
|
|
CaretPos,BaseURL,SmartHintStr,
|
|
[{$IFDEF EnableFocusHint}ihmchAddFocusHint{$ENDIF}])=shrSuccess
|
|
then
|
|
HasHint:=true;
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.OnSrcNotebookShowHintForSource B');{$ENDIF}
|
|
end;
|
|
case ToolStatus of
|
|
itDebugger: begin
|
|
if EditorOpts.AutoToolTipExprEval then begin
|
|
if SrcEdit.SelectionAvailable and SrcEdit.CaretInSelection(CaretPos) then
|
|
Expression := SrcEdit.GetText(True)
|
|
else
|
|
Expression := SrcEdit.GetOperandFromCaret(CaretPos);
|
|
if Expression='' then exit;
|
|
//DebugLn(['TMainIDE.OnSrcNotebookShowHintForSource Expression="',Expression,'"']);
|
|
DBGType:=nil;
|
|
DBGTypeDerefer:=nil;
|
|
Opts := [];
|
|
if EditorOpts.DbgHintAutoTypeCastClass
|
|
then Opts := [defClassAutoCast];
|
|
if not DebugBoss.Evaluate(Expression, DebugEval, DBGType, Opts) or (DebugEval = '') then
|
|
DebugEval := '???';
|
|
// deference a pointer - maybe it is a class
|
|
if Assigned(DBGType) and (DBGType.Kind in [skPointer]) and
|
|
not( StringCase(Lowercase(DBGType.TypeName), ['char', 'character', 'ansistring']) in [0..2] )
|
|
then
|
|
begin
|
|
if DBGType.Value.AsPointer <> nil then
|
|
begin
|
|
if DebugBoss.Evaluate(Expression + '^', DebugEvalDerefer, DBGTypeDerefer, Opts) then
|
|
begin
|
|
if Assigned(DBGTypeDerefer) and
|
|
( (DBGTypeDerefer.Kind <> skPointer) or
|
|
(StringCase(Lowercase(DBGTypeDerefer.TypeName), ['char', 'character', 'ansistring']) in [0..2])
|
|
)
|
|
then
|
|
DebugEval := DebugEval + ' = ' + DebugEvalDerefer;
|
|
end;
|
|
end;
|
|
end;
|
|
FreeAndNil(DBGType);
|
|
FreeAndNil(DBGTypeDerefer);
|
|
HasHint:=true;
|
|
Expression := Expression + ' = ' + DebugEval;
|
|
if SmartHintStr<>'' then begin
|
|
p:=System.Pos('<body>',lowercase(SmartHintStr));
|
|
if p>0 then begin
|
|
Insert('<div class="debuggerhint">'
|
|
+CodeHelpBoss.TextToHTML(Expression)+'</div><br>',
|
|
SmartHintStr,p+length('<body>'));
|
|
end else begin
|
|
SmartHintStr:=Expression+LineEnding+LineEnding+SmartHintStr;
|
|
end;
|
|
end else
|
|
SmartHintStr:=Expression;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if HasHint then
|
|
SrcEdit.ActivateHint(ClientPos, BaseURL, SmartHintStr);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNoteBookActivated(Sender: TObject);
|
|
begin
|
|
FDisplayState:= dsSource;
|
|
end;
|
|
|
|
procedure TMainIDE.OnDesignerActivated(Sender: TObject);
|
|
begin
|
|
FDisplayState:= dsForm;
|
|
FLastFormActivated := (Sender as TDesigner).Form;
|
|
UpdateIDEComponentPalette;
|
|
end;
|
|
|
|
procedure TMainIDE.OnDesignerCloseQuery(Sender: TObject);
|
|
var
|
|
ADesigner: TDesigner;
|
|
ASrcEdit: TSourceEditor;
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
ADesigner:=TDesigner(Sender);
|
|
GetDesignerUnit(ADesigner,ASrcEdit,AnUnitInfo);
|
|
if AnUnitInfo.NeedsSaveToDisk
|
|
then begin
|
|
case IDEQuestionDialog(lisSaveChanges,
|
|
Format(lisSaveFileBeforeClosingForm, ['"',
|
|
AnUnitInfo.Filename, '"', #13, '"',
|
|
ADesigner.LookupRoot.Name, '"']),
|
|
mtConfirmation,[mrYes,mrNoToAll,lisNo,mrCancel],'') of
|
|
mrYes: begin
|
|
if DoSaveEditorFile(ASrcEdit,[sfCheckAmbiguousFiles])<>mrOk
|
|
then Exit;
|
|
end;
|
|
mrNoToAll:;
|
|
else
|
|
Exit;
|
|
end;
|
|
end;
|
|
CloseUnitComponent(AnUnitInfo,[]);
|
|
end;
|
|
|
|
procedure TMainIDE.OnDesignerRenameComponent(ADesigner: TDesigner;
|
|
AComponent: TComponent; const NewName: string);
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
BossResult: boolean;
|
|
OldName: String;
|
|
OldClassName: String;
|
|
|
|
procedure ApplyBossResult(const ErrorMsg: string);
|
|
var
|
|
CodeToolBossErrMsg: String;
|
|
begin
|
|
ApplyCodeToolChanges;
|
|
if not BossResult then begin
|
|
CodeToolBossErrMsg:=CodeToolBoss.ErrorMessage;
|
|
DoJumpToCodeToolBossError;
|
|
raise Exception.Create(ErrorMsg+#13#13+lisError+CodeToolBossErrMsg
|
|
+#13#13+lisSeeMessages);
|
|
end;
|
|
end;
|
|
|
|
procedure CheckInterfaceName(const AName: string);
|
|
var
|
|
i: LongInt;
|
|
RegComp: TRegisteredComponent;
|
|
ConflictingClass: TClass;
|
|
s: string;
|
|
begin
|
|
if SysUtils.CompareText(ActiveUnitInfo.Unit_Name,AName)=0 then
|
|
raise Exception.Create(Format(
|
|
lisTheUnitItselfHasAlreadyTheNamePascalIdentifiersMus, ['"', AName, '"']
|
|
));
|
|
if ActiveUnitInfo.IsPartOfProject then begin
|
|
// check if component name already exists in project
|
|
i:=Project1.IndexOfUnitWithComponentName(AName,true,ActiveUnitInfo);
|
|
if i>=0 then
|
|
raise Exception.Create(
|
|
Format(lisThereIsAlreadyAFormWithTheName, ['"',
|
|
AName, '"']));
|
|
// check if pascal identifier already exists in the units
|
|
i:=Project1.IndexOfUnitWithName(AName,true,nil);
|
|
if i>=0 then
|
|
raise Exception.Create(Format(
|
|
lisThereIsAlreadyAUnitWithTheNamePascalIdentifiersMus, ['"', AName,
|
|
'"']));
|
|
end;
|
|
|
|
// check if classname
|
|
ConflictingClass:=AComponent.ClassType.ClassParent;
|
|
while ConflictingClass<>nil do begin
|
|
if SysUtils.CompareText(AName,ConflictingClass.ClassName)=0 then begin
|
|
s:='This component has already the class '+ConflictingClass.ClassName;
|
|
raise EComponentError.Create(s);
|
|
end;
|
|
ConflictingClass:=ConflictingClass.ClassParent;
|
|
end;
|
|
|
|
// check if keyword
|
|
if CodeToolBoss.IsKeyWord(ActiveUnitInfo.Source,AName) then
|
|
raise Exception.Create(Format(lisComponentNameIsKeyword, ['"', AName, '"']
|
|
));
|
|
|
|
// check if registered component class
|
|
RegComp:=IDEComponentPalette.FindComponent(AName);
|
|
if RegComp<>nil then begin
|
|
s:='There is already a component class with the name '+RegComp.ComponentClass.ClassName;
|
|
raise EComponentError.Create(s);
|
|
end;
|
|
end;
|
|
|
|
procedure RenameInheritedComponents(RenamedUnit: TUnitInfo;
|
|
Simulate: boolean);
|
|
var
|
|
UsedByDependency: TUnitComponentDependency;
|
|
DependingUnit: TUnitInfo;
|
|
InheritedComponent: TComponent;
|
|
DependingDesigner: TCustomForm;
|
|
begin
|
|
UsedByDependency:=ActiveUnitInfo.FirstUsedByComponent;
|
|
while UsedByDependency<>nil do begin
|
|
DependingUnit:=UsedByDependency.UsedByUnit;
|
|
if (DependingUnit.Component<>nil)
|
|
and (DependingUnit.Component.ClassParent=RenamedUnit.Component.ClassType)
|
|
then begin
|
|
// the root component inherits from the DependingUnit root component
|
|
if DependingUnit.Component.ClassParent=AComponent.ClassType then begin
|
|
if OldClassName<>AComponent.ClassName then begin
|
|
// replace references to classname, ignoring errors
|
|
CodeToolBoss.ReplaceWord(DependingUnit.Source,
|
|
OldClassName,AComponent.ClassName,false);
|
|
end;
|
|
end;
|
|
|
|
// rename inherited component
|
|
InheritedComponent:=
|
|
DependingUnit.Component.FindComponent(AComponent.Name);
|
|
if InheritedComponent<>nil then begin
|
|
// inherited component found
|
|
if FRenamingComponents=nil then
|
|
FRenamingComponents:=TFPList.Create;
|
|
FRenamingComponents.Add(InheritedComponent);
|
|
try
|
|
DebugLn(['RenameInheritedComponents ',dbgsName(InheritedComponent),' Owner=',dbgsName(InheritedComponent.Owner)]);
|
|
if Simulate then begin
|
|
// only check if rename is possible
|
|
if (InheritedComponent.Owner<>nil)
|
|
and (InheritedComponent.Owner.FindComponent(NewName)<>nil) then
|
|
begin
|
|
raise EComponentError.Createfmt(
|
|
lisDuplicateNameAComponentNamedAlreadyExistsInTheInhe, ['"',
|
|
NewName, '"', dbgsName(InheritedComponent.Owner)]);
|
|
end;
|
|
end else begin
|
|
// rename component and references in code
|
|
InheritedComponent.Name:=NewName;
|
|
DependingDesigner:=GetDesignerFormOfSource(DependingUnit,false);
|
|
if DependingDesigner<>nil then
|
|
DependingUnit.Modified:=true;
|
|
// replace references, ignoring errors
|
|
CodeToolBoss.ReplaceWord(DependingUnit.Source,OldName,NewName,
|
|
false);
|
|
end;
|
|
finally
|
|
if FRenamingComponents<>nil then begin
|
|
FRenamingComponents.Remove(InheritedComponent);
|
|
if FRenamingComponents.Count=0 then
|
|
FreeThenNil(FRenamingComponents);
|
|
end;
|
|
end;
|
|
end;
|
|
// rename recursively
|
|
RenameInheritedComponents(DependingUnit,Simulate);
|
|
end;
|
|
UsedByDependency:=UsedByDependency.NextUsedByDependency;
|
|
end;
|
|
end;
|
|
|
|
procedure RenameMethods;
|
|
var
|
|
PropList: PPropList;
|
|
PropCount: LongInt;
|
|
i: Integer;
|
|
PropInfo: PPropInfo;
|
|
DefaultName: Shortstring;
|
|
CurMethod: TMethod;
|
|
Root: TComponent;
|
|
CurMethodName: Shortstring;
|
|
RootClassName: ShortString;
|
|
NewMethodName: String;
|
|
CTResult: Boolean;
|
|
RenamedMethods: TStringList;
|
|
begin
|
|
PropCount:=GetPropList(PTypeInfo(AComponent.ClassInfo),PropList);
|
|
if PropCount=0 then exit;
|
|
RenamedMethods:=nil;
|
|
try
|
|
Root:=ActiveUnitInfo.Component;
|
|
RootClassName:=Root.ClassName;
|
|
if Root=AComponent then RootClassName:=OldClassName;
|
|
for i:=0 to PropCount-1 do begin
|
|
PropInfo:=PropList^[i];
|
|
if PropInfo^.PropType^.Kind<>tkMethod then continue;
|
|
CurMethod:=GetMethodProp(AComponent,PropInfo);
|
|
if (CurMethod.Data=nil) and (CurMethod.Code=nil) then continue;
|
|
CurMethodName:=GlobalDesignHook.GetMethodName(CurMethod,Root);
|
|
if CurMethodName='' then continue;
|
|
DefaultName:=TMethodPropertyEditor.GetDefaultMethodName(
|
|
Root,AComponent,RootClassName,OldName,PropInfo^.Name);
|
|
if (DefaultName<>CurMethodName) then continue;
|
|
// this method has the default name (component name + method type name)
|
|
NewMethodName:=TMethodPropertyEditor.GetDefaultMethodName(
|
|
Root,AComponent,Root.ClassName,NewName,PropInfo^.Name);
|
|
if (CurMethodName=NewMethodName) then continue;
|
|
// auto rename it
|
|
DebugLn(['RenameMethods OldMethodName="',DefaultName,'" NewMethodName="',NewMethodName,'"']);
|
|
|
|
// rename/create published method in source
|
|
CTResult:=CodeToolBoss.RenamePublishedMethod(ActiveUnitInfo.Source,
|
|
ActiveUnitInfo.Component.ClassName,CurMethodName,NewMethodName);
|
|
if CTResult then begin
|
|
// renamed in source, now rename in JIT class
|
|
FormEditor1.RenameJITMethod(ActiveUnitInfo.Component,
|
|
CurMethodName,NewMethodName);
|
|
// add to the list of renamed methods
|
|
if RenamedMethods=nil then
|
|
RenamedMethods:=TStringList.Create;
|
|
RenamedMethods.Add(CurMethodName);
|
|
RenamedMethods.Add(NewMethodName);
|
|
end else begin
|
|
// unable to rename method in source
|
|
// this is just a nice to have feature -> ignore the error
|
|
DebugLn(['TMainIDE.OnDesignerRenameComponent.RenameMethods failed OldMethodName="',CurMethodName,'" NewMethodName="',NewMethodName,'" Error=',CodeToolBoss.ErrorMessage]);
|
|
end;
|
|
end;
|
|
ApplyCodeToolChanges;
|
|
finally
|
|
FreeMem(PropList);
|
|
if RenamedMethods<>nil then begin
|
|
RenameInheritedMethods(ActiveUnitInfo,RenamedMethods);
|
|
RenamedMethods.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
NewClassName: string;
|
|
AncestorRoot: TComponent;
|
|
s: String;
|
|
OldOpenEditorsOnCodeToolChange: Boolean;
|
|
begin
|
|
DebugLn('TMainIDE.OnDesignerRenameComponent Old=',AComponent.Name,':',AComponent.ClassName,' New=',NewName,' Owner=',dbgsName(AComponent.Owner));
|
|
if (not IsValidIdent(NewName)) or (NewName='') then
|
|
raise Exception.Create(Format(lisComponentNameIsNotAValidIdentifier, ['"',
|
|
Newname, '"']));
|
|
if WordIsKeyWord.DoItCaseInsensitive(PChar(NewName))
|
|
or WordIsDelphiKeyWord.DoItCaseInsensitive(PChar(NewName))
|
|
or WordIsPredefinedFPCIdentifier.DoItCaseInsensitive(PChar(NewName))
|
|
or WordIsPredefinedDelphiIdentifier.DoItCaseInsensitive(PChar(NewName))
|
|
then begin
|
|
raise Exception.Create(Format(lisComponentNameIsAPascalKeyword, [NewName]));
|
|
end;
|
|
if AComponent.Name='' then begin
|
|
// this component was never added to the source. It is a new component.
|
|
exit;
|
|
end;
|
|
|
|
if (FRenamingComponents<>nil)
|
|
and (FRenamingComponents.IndexOf(AComponent)>=0) then begin
|
|
// already validated
|
|
exit;
|
|
end;
|
|
|
|
if SysUtils.CompareText(AComponent.Name,'Owner')=0 then begin
|
|
// 'Owner' is used by TReader/TWriter
|
|
raise EComponentError.Create(
|
|
lisOwnerIsAlreadyUsedByTReaderTWriterPleaseChooseAnot);
|
|
exit;
|
|
end;
|
|
|
|
BeginCodeTool(ADesigner,ActiveSrcEdit,ActiveUnitInfo,[ctfSwitchToFormSource]);
|
|
ActiveUnitInfo:=Project1.UnitWithComponent(ADesigner.LookupRoot);
|
|
|
|
OldName:=AComponent.Name;
|
|
OldClassName:=AComponent.ClassName;
|
|
NewClassName:='';
|
|
CheckInterfaceName(NewName);
|
|
if AComponent=ADesigner.LookupRoot then begin
|
|
// rename owner component (e.g. the form)
|
|
NewClassName:='T'+NewName;
|
|
CheckInterfaceName(NewClassName);
|
|
end;
|
|
|
|
OldOpenEditorsOnCodeToolChange:=OpenEditorsOnCodeToolChange;
|
|
OpenEditorsOnCodeToolChange:=true;
|
|
try
|
|
|
|
// check ancestor component
|
|
AncestorRoot:=FormEditor1.GetAncestorLookupRoot(AComponent);
|
|
if AncestorRoot<>nil then begin
|
|
s:=Format(lisTheComponentIsInheritedFromToRenameAnInheritedComp, [dbgsName
|
|
(AComponent), dbgsName(AncestorRoot), #13]);
|
|
raise EComponentError.Create(s);
|
|
end;
|
|
|
|
// check inherited components
|
|
RenameInheritedComponents(ActiveUnitInfo,true);
|
|
|
|
if AComponent=ADesigner.LookupRoot then begin
|
|
// rename owner component (e.g. the form)
|
|
|
|
// rename form component in source
|
|
BossResult:=CodeToolBoss.RenameForm(ActiveUnitInfo.Source,
|
|
AComponent.Name,AComponent.ClassName,
|
|
NewName,NewClassName);
|
|
ApplyBossResult(Format(lisUnableToRenameFormInSource, [#13]));
|
|
ActiveUnitInfo.ComponentName:=NewName;
|
|
|
|
// rename form component class
|
|
FormEditor1.RenameJITComponent(AComponent,NewClassName);
|
|
|
|
// change createform statement
|
|
if ActiveUnitInfo.IsPartOfProject and (Project1.MainUnitID>=0)
|
|
then begin
|
|
BossResult:=CodeToolBoss.ChangeCreateFormStatement(
|
|
Project1.MainUnitInfo.Source,
|
|
AComponent.ClassName,AComponent.Name,
|
|
NewClassName,NewName,true);
|
|
Project1.MainUnitInfo.Modified:=true;
|
|
ApplyBossResult(lisUnableToUpdateCreateFormStatementInProjectSource);
|
|
end;
|
|
end else if ADesigner.LookupRoot<>nil then begin
|
|
// rename published variable in form source
|
|
BossResult:=CodeToolBoss.RenamePublishedVariable(ActiveUnitInfo.Source,
|
|
ADesigner.LookupRoot.ClassName,
|
|
AComponent.Name,NewName,AComponent.ClassName,true);
|
|
ApplyBossResult(Format(lisUnableToRenameVariableInSource, [#13])
|
|
);
|
|
end else begin
|
|
RaiseException('TMainIDE.OnDesignerRenameComponent internal error:'+AComponent.Name+':'+AComponent.ClassName);
|
|
end;
|
|
|
|
// rename inherited components
|
|
RenameInheritedComponents(ActiveUnitInfo,false);
|
|
// mark references modified
|
|
MarkUnitsModifiedUsingSubComponent(AComponent);
|
|
|
|
// rename methods
|
|
RenameMethods;
|
|
finally
|
|
OpenEditorsOnCodeToolChange:=OldOpenEditorsOnCodeToolChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnDesignerViewLFM(Sender: TObject);
|
|
var
|
|
ADesigner: TDesigner;
|
|
ASrcEdit: TSourceEditor;
|
|
AnUnitInfo: TUnitInfo;
|
|
EditorInfo: TUnitEditorInfo;
|
|
LFMFilename: String;
|
|
begin
|
|
ADesigner:=TDesigner(Sender);
|
|
GetDesignerUnit(ADesigner,ASrcEdit,AnUnitInfo);
|
|
debugln('TMainIDE.OnDesignerViewLFM ',AnUnitInfo.Filename);
|
|
OnDesignerCloseQuery(Sender);
|
|
if AnUnitInfo.OpenEditorInfoCount > 0 then
|
|
EditorInfo := AnUnitInfo.OpenEditorInfo[0]
|
|
else
|
|
EditorInfo := AnUnitInfo.EditorInfo[0];
|
|
LFMFilename:=ChangeFileExt(AnUnitInfo.Filename, '.lfm');
|
|
if not FileExistsUTF8(LFMFilename) then
|
|
LFMFilename:=ChangeFileExt(AnUnitInfo.Filename, '.dfm');
|
|
DoOpenEditorFile(LFMFilename, EditorInfo.PageIndex+1, EditorInfo.WindowIndex, []);
|
|
end;
|
|
|
|
procedure TMainIDE.OnDesignerSaveAsXML(Sender: TObject);
|
|
var
|
|
SaveDialog: TSaveDialog;
|
|
SaveAsFilename: String;
|
|
SaveAsFileExt: String;
|
|
PkgDefaultDirectory: String;
|
|
Filename: String;
|
|
XMLConfig: TXMLConfig;
|
|
ADesigner: TDesigner;
|
|
ASrcEdit: TSourceEditor;
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
ADesigner:=TDesigner(Sender);
|
|
GetDesignerUnit(ADesigner,ASrcEdit,AnUnitInfo);
|
|
debugln('TMainIDE.OnDesignerViewLFM ',AnUnitInfo.Filename);
|
|
|
|
SaveAsFileExt:='.xml';
|
|
SaveAsFilename:=ChangeFileExt(AnUnitInfo.Filename,SaveAsFileExt);
|
|
SaveDialog:=TSaveDialog.Create(nil);
|
|
try
|
|
InputHistories.ApplyFileDialogSettings(SaveDialog);
|
|
SaveDialog.Title:=lisSaveSpace+SaveAsFilename+' (*'+SaveAsFileExt+')';
|
|
SaveDialog.FileName:=SaveAsFilename;
|
|
// if this is a project file, start in project directory
|
|
if AnUnitInfo.IsPartOfProject and (not Project1.IsVirtual)
|
|
and (not FileIsInPath(SaveDialog.InitialDir,Project1.ProjectDirectory)) then
|
|
begin
|
|
SaveDialog.InitialDir:=Project1.ProjectDirectory;
|
|
end;
|
|
// if this is a package file, then start in package directory
|
|
PkgDefaultDirectory:=
|
|
PkgBoss.GetDefaultSaveDirectoryForFile(AnUnitInfo.Filename);
|
|
if (PkgDefaultDirectory<>'')
|
|
and (not FileIsInPath(SaveDialog.InitialDir,PkgDefaultDirectory)) then
|
|
SaveDialog.InitialDir:=PkgDefaultDirectory;
|
|
// show save dialog
|
|
if (not SaveDialog.Execute) or (ExtractFileName(SaveDialog.Filename)='')
|
|
then begin
|
|
// user cancels
|
|
exit;
|
|
end;
|
|
Filename:=ExpandFileNameUTF8(SaveDialog.Filename);
|
|
finally
|
|
InputHistories.StoreFileDialogSettings(SaveDialog);
|
|
SaveDialog.Free;
|
|
end;
|
|
|
|
try
|
|
XMLConfig:=TXMLConfig.Create(Filename);
|
|
try
|
|
WriteComponentToXMLConfig(XMLConfig,'Component',ADesigner.LookupRoot);
|
|
XMLConfig.Flush;
|
|
finally
|
|
XMLConfig.Free;
|
|
end;
|
|
except
|
|
on E: Exception do begin
|
|
MessageDlg('Error',E.Message,mtError,[mbCancel],0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnDesignerShowObjectInspector(Sender: TObject);
|
|
begin
|
|
DoBringToFrontFormOrInspector(True);
|
|
end;
|
|
|
|
procedure TMainIDE.OnDesignerShowAnchorEditor(Sender: TObject);
|
|
begin
|
|
DoViewAnchorEditor(True);
|
|
end;
|
|
|
|
procedure TMainIDE.OnDesignerShowTabOrderEditor(Sender: TObject);
|
|
begin
|
|
DoViewTabOrderEditor(True);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNoteBookAddJumpPoint(ACaretXY: TPoint;
|
|
ATopLine: integer; AEditor: TSourceEditor; DeleteForwardHistory: boolean);
|
|
{off $DEFINE VerboseJumpHistory}
|
|
var
|
|
ActiveUnitInfo: TUnitInfo;
|
|
NewJumpPoint: TProjectJumpHistoryPosition;
|
|
begin
|
|
{$IFDEF VerboseJumpHistory}
|
|
writeln('');
|
|
writeln('[TMainIDE.OnSrcNoteBookAddJumpPoint] A Line=',ACaretXY.Y,' Col=',ACaretXY.X,' DeleteForwardHistory=',DeleteForwardHistory,' Count=',Project1.JumpHistory.Count,',HistoryIndex=',Project1.JumpHistory.HistoryIndex);
|
|
{$ENDIF}
|
|
ActiveUnitInfo:=Project1.UnitWithEditorComponent(AEditor);
|
|
if (ActiveUnitInfo=nil) then exit;
|
|
NewJumpPoint:=TProjectJumpHistoryPosition.Create(ActiveUnitInfo.Filename,
|
|
ACaretXY,ATopLine);
|
|
{$IFDEF VerboseJumpHistory}
|
|
//Project1.JumpHistory.WriteDebugReport;
|
|
{$ENDIF}
|
|
Project1.JumpHistory.InsertSmart(Project1.JumpHistory.HistoryIndex+1,
|
|
NewJumpPoint);
|
|
{$IFDEF VerboseJumpHistory}
|
|
writeln('[TMainIDE.OnSrcNoteBookAddJumpPoint] B INSERTED');
|
|
Project1.JumpHistory.WriteDebugReport;
|
|
{$ENDIF}
|
|
if DeleteForwardHistory then Project1.JumpHistory.DeleteForwardHistory;
|
|
{$IFDEF VerboseJumpHistory}
|
|
writeln('[TMainIDE.OnSrcNoteBookAddJumpPoint] END Line=',ACaretXY.Y,',DeleteForwardHistory=',DeleteForwardHistory,' Count=',Project1.JumpHistory.Count,',HistoryIndex=',Project1.JumpHistory.HistoryIndex);
|
|
Project1.JumpHistory.WriteDebugReport;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookDeleteLastJumPoint(Sender: TObject);
|
|
begin
|
|
Project1.JumpHistory.DeleteLast;
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookJumpToHistoryPoint(var NewCaretXY: TPoint;
|
|
var NewTopLine: integer; var DestEditor: TSourceEditor;
|
|
JumpAction: TJumpHistoryAction);
|
|
{ How the HistoryIndex works:
|
|
|
|
When the user jumps around each time an item is added to the history list
|
|
and the HistoryIndex points to the last added item (i.e. Count-1).
|
|
|
|
Jumping back:
|
|
The sourceditor will be repositioned to the item with the HistoryIndex.
|
|
Then the historyindex is moved to the previous item.
|
|
If HistoryIndex is the last item in the history, then this is the first
|
|
back jump and the current sourceeditor position is smart added to the
|
|
history list. Smart means that if the added Item is similar to the last
|
|
item then the last item will be replaced else a new item is added.
|
|
|
|
Jumping forward:
|
|
|
|
}
|
|
var DestIndex, UnitIndex: integer;
|
|
ASrcEdit: TSourceEditor;
|
|
AnUnitInfo: TUnitInfo;
|
|
DestJumpPoint: TProjectJumpHistoryPosition;
|
|
CursorPoint, NewJumpPoint: TProjectJumpHistoryPosition;
|
|
JumpHistory : TProjectJumpHistory;
|
|
AnEditorInfo: TUnitEditorInfo;
|
|
begin
|
|
DestEditor := nil;
|
|
NewCaretXY.Y:=-1;
|
|
JumpHistory:=Project1.JumpHistory;
|
|
|
|
{$IFDEF VerboseJumpHistory}
|
|
writeln('');
|
|
writeln('[TMainIDE.OnSrcNotebookJumpToHistoryPoint] A Back=',JumpAction=jhaBack);
|
|
JumpHistory.WriteDebugReport;
|
|
{$ENDIF}
|
|
|
|
// update jump history (e.g. delete jumps to closed editors)
|
|
JumpHistory.DeleteInvalidPositions;
|
|
|
|
// get destination jump point
|
|
DestIndex:=JumpHistory.HistoryIndex;
|
|
|
|
CursorPoint:=nil;
|
|
// get current cursor position
|
|
GetCurrentUnit(ASrcEdit,AnUnitInfo);
|
|
if (ASrcEdit<>nil) and (AnUnitInfo<>nil) then begin
|
|
CursorPoint:=TProjectJumpHistoryPosition.Create
|
|
(AnUnitInfo.Filename,
|
|
ASrcEdit.EditorComponent.LogicalCaretXY,
|
|
ASrcEdit.EditorComponent.TopLine
|
|
);
|
|
{$IFDEF VerboseJumpHistory}
|
|
writeln(' Current Position: ',CursorPoint.Filename,
|
|
' ',CursorPoint.CaretXY.X,',',CursorPoint.CaretXY.Y-1);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
if (JumpAction=jhaBack) and (JumpHistory.Count=DestIndex+1)
|
|
and (CursorPoint<>nil) then begin
|
|
// this is the first back jump
|
|
// -> insert current source position into history
|
|
{$IFDEF VerboseJumpHistory}
|
|
writeln(' First back jump -> add current cursor position');
|
|
{$ENDIF}
|
|
NewJumpPoint:=TProjectJumpHistoryPosition.Create(CursorPoint);
|
|
JumpHistory.InsertSmart(JumpHistory.HistoryIndex+1, NewJumpPoint);
|
|
end;
|
|
|
|
// find the next jump point that is not where the cursor is
|
|
case JumpAction of
|
|
jhaForward : inc(DestIndex);
|
|
// jhaBack : if (CursorPoint<>nil) and (JumpHistory[DestIndex].IsSimilar(CursorPoint))
|
|
// then dec(DestIndex);
|
|
jhaViewWindow : DestIndex := JumpHistoryViewWin.SelectedIndex;
|
|
end;
|
|
|
|
while (DestIndex>=0) and (DestIndex<JumpHistory.Count) do begin
|
|
DestJumpPoint:=JumpHistory[DestIndex];
|
|
UnitIndex:=Project1.IndexOfFilename(DestJumpPoint.Filename);
|
|
{$IFDEF VerboseJumpHistory}
|
|
writeln(' DestIndex=',DestIndex,' UnitIndex=',UnitIndex);
|
|
{$ENDIF}
|
|
if (UnitIndex >= 0) and (Project1.Units[UnitIndex].OpenEditorInfoCount > 0)
|
|
and ((CursorPoint=nil) or not DestJumpPoint.IsSimilar(CursorPoint)) then
|
|
begin
|
|
JumpHistory.HistoryIndex:=DestIndex;
|
|
NewCaretXY:=DestJumpPoint.CaretXY;
|
|
NewTopLine:=DestJumpPoint.TopLine;
|
|
AnEditorInfo := GetAvailableUnitEditorInfo(Project1.Units[UnitIndex], NewCaretXY);
|
|
if AnEditorInfo <> nil then
|
|
DestEditor:=TSourceEditor(AnEditorInfo.EditorComponent);
|
|
{$IFDEF VerboseJumpHistory}
|
|
writeln('[TMainIDE.OnSrcNotebookJumpToHistoryPoint] Result Line=',NewCaretXY.Y,' Col=',NewCaretXY.X);
|
|
{$ENDIF}
|
|
break;
|
|
end;
|
|
case JumpAction of
|
|
jhaForward : inc(DestIndex);
|
|
jhaBack : dec(DestIndex);
|
|
jhaViewWindow : break;
|
|
end;
|
|
end;
|
|
|
|
CursorPoint.Free;
|
|
|
|
{$IFDEF VerboseJumpHistory}
|
|
writeln('[TMainIDE.OnSrcNotebookJumpToHistoryPoint] END Count=',JumpHistory.Count,',HistoryIndex=',JumpHistory.HistoryIndex);
|
|
JumpHistory.WriteDebugReport;
|
|
writeln('');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNoteBookMouseLink(
|
|
Sender: TObject; X, Y: Integer; var AllowMouseLink: Boolean);
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
NewSource: TCodeBuffer;
|
|
NewX, NewY, NewTopLine: integer;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
AllowMouseLink := CodeToolBoss.FindDeclaration(
|
|
ActiveUnitInfo.Source,X,Y,NewSource,NewX,NewY,NewTopLine);
|
|
end;
|
|
|
|
function TMainIDE.OnSrcNoteBookGetIndent(Sender: TObject;
|
|
SrcEditor: TSourceEditor; LogCaret, OldLogCaret: TPoint;
|
|
FirstLinePos, LastLinePos: Integer; Reason: TSynEditorCommand;
|
|
SetIndentProc: TSynBeautifierSetIndentProc): Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookReadOnlyChanged(Sender: TObject);
|
|
var
|
|
ActiveSourceEditor: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
begin
|
|
GetCurrentUnit(ActiveSourceEditor,ActiveUnitInfo);
|
|
ActiveUnitInfo.UserReadOnly:=ActiveSourceEditor.ReadOnly;
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNotebookViewJumpHistory(Sender: TObject);
|
|
begin
|
|
DoViewJumpHistory(true);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNoteBookPopupMenu(
|
|
const AddMenuItemProc: TAddMenuItemProc);
|
|
begin
|
|
PkgBoss.OnSourceEditorPopupMenu(AddMenuItemProc);
|
|
end;
|
|
|
|
procedure TMainIDE.OnSrcNoteBookCloseQuery(Sender: TObject; var CloseAction: TCloseAction);
|
|
var
|
|
SrcNB: TSourceNotebook;
|
|
begin
|
|
if SourceEditorManager.SourceWindowCount = 1 then
|
|
exit;
|
|
|
|
SrcNB := TSourceNotebook(Sender);
|
|
if (SrcNB.EditorCount = 1) then begin
|
|
DoCloseEditorFile(SrcNB.Editors[0], []);
|
|
CloseAction := caFree;
|
|
exit;
|
|
end;
|
|
|
|
CloseAction := caHide;
|
|
case QuestionDlg(lisCloseAllTabsTitle, lisCloseAllTabsQuestion, mtConfirmation,
|
|
[mrYes, lisCloseAllTabsClose, mrNo, lisCloseAllTabsHide, mrCancel],
|
|
0)
|
|
of
|
|
mrYes : begin
|
|
SourceEditorManager.IncUpdateLock;
|
|
try
|
|
while (SrcNB.EditorCount > 0) and
|
|
(DoCloseEditorFile(SrcNB.Editors[0], [cfSaveFirst]) = mrOK)
|
|
do ;
|
|
if SrcNB.EditorCount = 0 then
|
|
CloseAction := caFree;
|
|
finally
|
|
SourceEditorManager.DecUpdateLock;
|
|
end;
|
|
end;
|
|
mrNo : CloseAction := caHide;
|
|
mrCancel : CloseAction := caNone;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnApplicationUserInput(Sender: TObject; Msg: Cardinal);
|
|
begin
|
|
fUserInputSinceLastIdle:=true;
|
|
if ToolStatus=itCodeTools then begin
|
|
// abort codetools
|
|
ToolStatus:=itCodeToolAborting;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnApplicationIdle(Sender: TObject; var Done: Boolean);
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
AnUnitInfo: TUnitInfo;
|
|
AnIDesigner: TIDesigner;
|
|
HasResources: Boolean;
|
|
begin
|
|
if FNeedUpdateHighlighters then
|
|
UpdateHighlighters(true);
|
|
GetDefaultProcessList.FreeStoppedProcesses;
|
|
ExternalTools.FreeStoppedProcesses;
|
|
if (SplashForm<>nil) then FreeThenNil(SplashForm);
|
|
|
|
if FUserInputSinceLastIdle then
|
|
begin
|
|
FUserInputSinceLastIdle:=false;
|
|
UpdateWindowMenu;
|
|
FormEditor1.CheckDesignerPositions;
|
|
FormEditor1.PaintAllDesignerItems;
|
|
GetCurrentUnit(SrcEdit,AnUnitInfo);
|
|
UpdateSaveMenuItemsAndButtons(true);
|
|
if Screen.ActiveForm<>nil then
|
|
begin
|
|
AnIDesigner:=Screen.ActiveForm.Designer;
|
|
if AnIDesigner is TDesigner then
|
|
MainIDEBar.itmViewToggleFormUnit.Enabled := true
|
|
else
|
|
begin
|
|
HasResources:=false;
|
|
if AnUnitInfo<>nil then
|
|
begin
|
|
if AnUnitInfo.HasResources then
|
|
HasResources:=true
|
|
else if FilenameIsAbsolute(AnUnitInfo.Filename)
|
|
and FilenameIsPascalSource(AnUnitInfo.Filename)
|
|
and ( FileExistsCached(ChangeFileExt(AnUnitInfo.Filename,'.lfm'))
|
|
or FileExistsCached(ChangeFileExt(AnUnitInfo.Filename,'.dfm')) )
|
|
then
|
|
HasResources:=true;
|
|
end;
|
|
MainIDEBar.itmViewToggleFormUnit.Enabled := HasResources;
|
|
end;
|
|
MainIDEBar.ToggleFormSpeedBtn.Enabled := MainIDEBar.itmViewToggleFormUnit.Enabled;
|
|
DebugBoss.UpdateButtonsAndMenuItems;
|
|
end;
|
|
end;
|
|
if FCheckFilesOnDiskNeeded then
|
|
DoCheckFilesOnDisk(true);
|
|
if (FRemoteControlTimer=nil) and EnableRemoteControl then
|
|
SetupRemoteControl;
|
|
if Screen.GetCurrentModalForm=nil then
|
|
PkgBoss.OpenHiddenModifiedPackages;
|
|
end;
|
|
|
|
procedure TMainIDE.OnApplicationDeActivate(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
AForm: TCustomForm;
|
|
begin
|
|
if EnvironmentOptions.SingleTaskBarButton and FApplicationIsActivate
|
|
and (MainIDEBar.WindowState=wsNormal) then
|
|
begin
|
|
for i:=Screen.CustomFormCount-1 downto 0 do
|
|
begin
|
|
AForm:=Screen.CustomFormsZOrdered[i];
|
|
if (AForm.Parent=nil) and (AForm<>MainIDEBar) and (AForm.IsVisible)
|
|
and (AForm.Designer=nil) and (not (csDesigning in AForm.ComponentState))
|
|
and not (fsModal in AForm.FormState) then
|
|
LastActivatedWindows.Add(AForm);
|
|
end;
|
|
FApplicationIsActivate:=false;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnMainBarActive(Sender: TObject);
|
|
var
|
|
i, FormCount: integer;
|
|
AForm: TCustomForm;
|
|
begin
|
|
if EnvironmentOptions.SingleTaskBarButton and not FApplicationIsActivate
|
|
and (MainIDEBar.WindowState=wsNormal) then
|
|
begin
|
|
FApplicationIsActivate:=true;
|
|
FormCount:=0;
|
|
for i:=Screen.CustomFormCount-1 downto 0 do
|
|
begin
|
|
AForm:=Screen.CustomForms[i];
|
|
if (AForm.Parent=nil) and (AForm<>MainIDEBar) and (AForm.IsVisible)
|
|
and (AForm.Designer=nil) and (not (csDesigning in AForm.ComponentState))
|
|
and not (fsModal in AForm.FormState) then
|
|
inc(FormCount);
|
|
end;
|
|
if FormCount<>LastActivatedWindows.Count then
|
|
LastActivatedWindows.Clear;
|
|
while LastActivatedWindows.Count>0 do
|
|
begin
|
|
AForm:=TCustomForm(LastActivatedWindows[0]);
|
|
if Assigned(AForm) and (not (CsDestroying in AForm.ComponentState)) and
|
|
AForm.IsVisible then
|
|
AForm.BringToFront;
|
|
LastActivatedWindows.Delete(0);
|
|
end;
|
|
MainIDEBar.BringToFront;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnApplicationActivate(Sender: TObject);
|
|
begin
|
|
DoCheckFilesOnDisk;
|
|
end;
|
|
|
|
procedure TMainIDE.OnApplicationKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
var
|
|
Command: Word;
|
|
begin
|
|
//DebugLn('TMainIDE.OnApplicationKeyDown ',dbgs(Key),' ',dbgs(Shift));
|
|
Command := EditorOpts.KeyMap.TranslateKey(Key,Shift,nil);
|
|
if Command=ecEditContextHelp then begin
|
|
Key:=VK_UNKNOWN;
|
|
ShowContextHelpEditor(Sender);
|
|
end else if (Command=ecContextHelp) and (Sender is TControl) then begin
|
|
Key:=VK_UNKNOWN;
|
|
LazarusHelp.ShowHelpForIDEControl(TControl(Sender));
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnApplicationDropFiles(Sender: TObject; const FileNames: array of String);
|
|
var
|
|
OpenFlags: TOpenFlags;
|
|
I: Integer;
|
|
AFilename: String;
|
|
begin
|
|
//debugln('TMainIDE.OnApplicationDropFiles FileNames=', dbgs(Length(FileNames)));
|
|
if Length(FileNames) > 0 then
|
|
begin
|
|
OpenFlags := [ofAddToRecent];
|
|
if Length(FileNames) > 1 then
|
|
Include(OpenFlags, ofRegularFile);
|
|
|
|
try
|
|
SourceEditorManager.IncUpdateLock;
|
|
for I := 0 to High(FileNames) do
|
|
begin
|
|
AFilename := CleanAndExpandFilename(FileNames[I]);
|
|
|
|
if I < High(FileNames) then
|
|
Include(OpenFlags, ofMultiOpen)
|
|
else
|
|
Exclude(OpenFlags, ofMultiOpen);
|
|
|
|
if DoOpenEditorFile(AFilename, -1, -1, OpenFlags) = mrAbort then Break;
|
|
end;
|
|
finally
|
|
SourceEditorManager.DecUpdateLock;
|
|
end;
|
|
|
|
SetRecentFilesMenu;
|
|
SaveEnvironment;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnApplicationQueryEndSession(var Cancel: Boolean);
|
|
begin
|
|
Cancel := False;
|
|
end;
|
|
|
|
procedure TMainIDE.OnApplicationEndSession(Sender: TObject);
|
|
begin
|
|
QuitIDE;
|
|
end;
|
|
|
|
procedure TMainIDE.OnScreenRemoveForm(Sender: TObject; AForm: TCustomForm);
|
|
begin
|
|
HiddenWindowsOnRun.Remove(AForm);
|
|
end;
|
|
|
|
procedure TMainIDE.OnRemoteControlTimer(Sender: TObject);
|
|
begin
|
|
FRemoteControlTimer.Enabled:=false;
|
|
DoExecuteRemoteControl;
|
|
FRemoteControlTimer.Enabled:=true;
|
|
end;
|
|
|
|
procedure TMainIDE.OnSelectFrame(Sender: TObject; var AComponentClass: TComponentClass);
|
|
begin
|
|
AComponentClass := DoSelectFrame;
|
|
end;
|
|
|
|
procedure TMainIDE.OIChangedTimerTimer(Sender: TObject);
|
|
var
|
|
OI: TObjectInspectorDlg;
|
|
ARow: TOIPropertyGridRow;
|
|
Code: TCodeBuffer;
|
|
Caret: TPoint;
|
|
NewTopLine: integer;
|
|
HtmlHint, BaseURL: string;
|
|
CacheWasUsed: Boolean;
|
|
Stream: TStringStream;
|
|
begin
|
|
OI:=ObjectInspector1;
|
|
if (OI=nil) or (not OI.IsVisible) then
|
|
Exit;
|
|
OIChangedTimer.AutoEnabled:=false;
|
|
OIChangedTimer.Enabled:=false;
|
|
|
|
if not BeginCodeTools or not OI.ShowInfoBox then
|
|
Exit;
|
|
|
|
HtmlHint := '';
|
|
BaseURL := '';
|
|
|
|
ARow := OI.GetActivePropertyRow;
|
|
|
|
if (ARow <> nil)
|
|
and FindDeclarationOfOIProperty(OI, ARow, Code, Caret, NewTopLine) then
|
|
begin
|
|
if CodeHelpBoss.GetHTMLHint(Code, Caret.X, Caret.Y, [],
|
|
BaseURL, HtmlHint, CacheWasUsed) <> chprSuccess then
|
|
begin
|
|
HtmlHint := '';
|
|
BaseURL := '';
|
|
end;
|
|
end;
|
|
|
|
if OI.InfoPanel.ControlCount > 0 then
|
|
OI.InfoPanel.Controls[0].Visible := HtmlHint <> '';
|
|
if HtmlHint <> '' then
|
|
begin
|
|
OIHelpProvider.BaseURL := BaseURL;
|
|
Stream := TStringStream.Create(HtmlHint);
|
|
try
|
|
OIHelpProvider.ControlIntf.SetHTMLContent(Stream);
|
|
finally
|
|
Stream.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuFileClicked(Sender: TObject);
|
|
var
|
|
ASrcEdit: TSourceEditor;
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
GetCurrentUnit(ASrcEdit,AnUnitInfo);
|
|
with MainIDEBar do begin
|
|
itmFileClose.Enabled := ASrcEdit<>nil;
|
|
itmFileCloseAll.Enabled := ASrcEdit<>nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.CheckDirIsInUnitSearchPath(UnitInfo: TUnitInfo;
|
|
AllowAddingDependencies: boolean; out DependencyAdded: boolean);
|
|
var
|
|
CurDirectory: String;
|
|
CurUnitPath: String;
|
|
Owners: TFPList;
|
|
i: Integer;
|
|
APackage: TLazPackage;
|
|
ShortDir: String;
|
|
begin
|
|
DependencyAdded:=false;
|
|
if UnitInfo.IsVirtual then exit;
|
|
CurUnitPath:=Project1.CompilerOptions.GetUnitPath(false);
|
|
CurDirectory:=AppendPathDelim(UnitInfo.GetDirectory);
|
|
if SearchDirectoryInSearchPath(CurUnitPath,CurDirectory)<1 then
|
|
begin
|
|
if AllowAddingDependencies then begin
|
|
Owners:=PkgBoss.GetPossibleOwnersOfUnit(UnitInfo.Filename,[]);
|
|
try
|
|
if (Owners<>nil) then begin
|
|
for i:=0 to Owners.Count-1 do begin
|
|
if TObject(Owners[i]) is TLazPackage then begin
|
|
APackage:=TLazPackage(Owners[i]);
|
|
if IDEMessageDialog(lisAddPackageRequirement,
|
|
Format(lisAddPackageToProject, [APackage.IDAsString]),
|
|
mtConfirmation,[mbYes,mbCancel],'')<>mrYes
|
|
then
|
|
exit;
|
|
PkgBoss.AddProjectDependency(Project1,APackage);
|
|
DependencyAdded:=true;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
Owners.Free;
|
|
end;
|
|
end;
|
|
// unit is not in a package => extend unit path
|
|
ShortDir:=CurDirectory;
|
|
if (not Project1.IsVirtual) then
|
|
ShortDir:=CreateRelativePath(ShortDir,Project1.ProjectDirectory);
|
|
if MessageDlg(lisAddToUnitSearchPath,
|
|
Format(lisTheNewUnitIsNotYetInTheUnitSearchPathAddDirectory, [
|
|
#13, CurDirectory]),
|
|
mtConfirmation,[mbYes,mbNo],0)=mrYes
|
|
then begin
|
|
Project1.CompilerOptions.OtherUnitFiles:=
|
|
MergeSearchPaths(Project1.CompilerOptions.OtherUnitFiles,ShortDir);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.CheckDirIsInIncludeSearchPath(UnitInfo: TUnitInfo;
|
|
AllowAddingDependencies: boolean; out DependencyAdded: boolean);
|
|
var
|
|
CurDirectory: String;
|
|
CurIncPath: String;
|
|
Owners: TFPList;
|
|
i: Integer;
|
|
APackage: TLazPackage;
|
|
ShortDir: String;
|
|
begin
|
|
DependencyAdded:=false;
|
|
if UnitInfo.IsVirtual then exit;
|
|
CurIncPath:=Project1.CompilerOptions.GetIncludePath(false);
|
|
CurDirectory:=AppendPathDelim(UnitInfo.GetDirectory);
|
|
if SearchDirectoryInSearchPath(CurIncPath,CurDirectory)<1 then
|
|
begin
|
|
if AllowAddingDependencies then begin
|
|
Owners:=PkgBoss.GetPossibleOwnersOfUnit(UnitInfo.Filename,[]);
|
|
try
|
|
if (Owners<>nil) then begin
|
|
for i:=0 to Owners.Count-1 do begin
|
|
if TObject(Owners[i]) is TLazPackage then begin
|
|
APackage:=TLazPackage(Owners[i]);
|
|
if IDEMessageDialog(lisAddPackageRequirement,
|
|
Format(lisAddPackageToProject, [APackage.IDAsString]),
|
|
mtConfirmation,[mbYes,mbCancel],'')<>mrYes
|
|
then
|
|
exit;
|
|
PkgBoss.AddProjectDependency(Project1,APackage);
|
|
DependencyAdded:=true;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
Owners.Free;
|
|
end;
|
|
end;
|
|
// include file is not in a package => extend include path
|
|
ShortDir:=CurDirectory;
|
|
if (not Project1.IsVirtual) then
|
|
ShortDir:=CreateRelativePath(ShortDir,Project1.ProjectDirectory);
|
|
if MessageDlg(lisAddToIncludeSearchPath,
|
|
Format(lisTheNewIncludeFileIsNotYetInTheIncludeSearchPathAdd, [#13,
|
|
CurDirectory]),
|
|
mtConfirmation,[mbYes,mbNo],0)=mrYes
|
|
then begin
|
|
Project1.CompilerOptions.IncludePath:=
|
|
MergeSearchPaths(Project1.CompilerOptions.IncludePath,ShortDir);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.ProjInspectorAddUnitToProject(Sender: TObject;
|
|
AnUnitInfo: TUnitInfo): TModalresult;
|
|
var
|
|
ActiveSourceEditor: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
ShortUnitName: String;
|
|
Dummy: Boolean;
|
|
DependencyAdded: boolean;
|
|
begin
|
|
Result:=mrOk;
|
|
//debugln(['TMainIDE.ProjInspectorAddUnitToProject ',AnUnitInfo.Filename]);
|
|
BeginCodeTool(ActiveSourceEditor,ActiveUnitInfo,[]);
|
|
AnUnitInfo.IsPartOfProject:=true;
|
|
DependencyAdded:=false;
|
|
if FilenameIsPascalUnit(AnUnitInfo.Filename) then
|
|
CheckDirIsInUnitSearchPath(AnUnitInfo,false,DependencyAdded)
|
|
else if CompareFileExt(AnUnitInfo.Filename,'inc',false)=0 then
|
|
CheckDirIsInIncludeSearchPath(AnUnitInfo,false,DependencyAdded);
|
|
if FilenameIsPascalUnit(AnUnitInfo.Filename)
|
|
and (pfMainUnitHasUsesSectionForAllUnits in Project1.Flags)
|
|
then begin
|
|
AnUnitInfo.ReadUnitNameFromSource(false);
|
|
ShortUnitName:=AnUnitInfo.Unit_Name;
|
|
if (ShortUnitName<>'') then begin
|
|
Dummy:=CodeToolBoss.AddUnitToMainUsesSection(
|
|
Project1.MainUnitInfo.Source,ShortUnitName,'');
|
|
ApplyCodeToolChanges;
|
|
if Dummy then begin
|
|
Project1.MainUnitInfo.Modified:=true;
|
|
end else begin
|
|
DoJumpToCodeToolBossError;
|
|
Result:=mrCancel;
|
|
end;
|
|
end;
|
|
end;
|
|
Project1.Modified:=true;
|
|
end;
|
|
|
|
function TMainIDE.ProjInspectorRemoveFile(Sender: TObject; AnUnitInfo: TUnitInfo
|
|
): TModalresult;
|
|
var
|
|
UnitInfos: TFPList;
|
|
begin
|
|
if not AnUnitInfo.IsPartOfProject then exit(mrOk);
|
|
UnitInfos:=TFPList.Create;
|
|
try
|
|
UnitInfos.Add(AnUnitInfo);
|
|
Result:=RemoveFilesFromProject(Project1,UnitInfos);
|
|
finally
|
|
UnitInfos.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnCompilerOptionsDialogTest(Sender: TObject);
|
|
begin
|
|
DoTestCompilerSettings(Sender as TCompilerOptions);
|
|
end;
|
|
|
|
function TMainIDE.OnCheckCompOptsAndMainSrcForNewUnit(
|
|
CompOpts: TLazCompilerOptions): TModalResult;
|
|
begin
|
|
Result:=CheckCompOptsAndMainSrcForNewUnit(CompOpts);
|
|
end;
|
|
|
|
procedure TMainIDE.ProjInspectorOpen(Sender: TObject);
|
|
var
|
|
CurUnitInfo: TUnitInfo;
|
|
begin
|
|
CurUnitInfo:=ProjInspector.GetSelectedFile;
|
|
if CurUnitInfo<>nil then begin
|
|
DoOpenEditorFile(CurUnitInfo.Filename,-1,-1,[ofRegularFile]);
|
|
exit;
|
|
end;
|
|
if PkgBoss.OnProjectInspectorOpen(Sender) then exit;
|
|
end;
|
|
|
|
procedure TMainIDE.OnExtToolNeedsOutputFilter(var OutputFilter: TOutputFilter;
|
|
var Abort: boolean);
|
|
begin
|
|
OutputFilter:=TheOutputFilter;
|
|
if ToolStatus<>itNone then begin
|
|
Abort:=true;
|
|
exit;
|
|
end;
|
|
SourceEditorManager.ClearErrorLines;
|
|
|
|
ToolStatus:=itBuilder;
|
|
MessagesView.Clear;
|
|
DoArrangeSourceEditorAndMessageView(false);
|
|
ConnectOutputFilter;
|
|
end;
|
|
|
|
procedure TMainIDE.OnExtToolFreeOutputFilter(OutputFilter: TOutputFilter;
|
|
ErrorOccurred: boolean);
|
|
begin
|
|
if ToolStatus=itBuilder then
|
|
ToolStatus:=itNone;
|
|
if ErrorOccurred then
|
|
DoJumpToCompilerMessage(-1,true);
|
|
end;
|
|
|
|
procedure TMainIDE.OnGetLayout(Sender: TObject; aFormName: string; out
|
|
aBounds: TRect; out DockSibling: string; out DockAlign: TAlign);
|
|
var
|
|
SrcEditWnd: TSourceNotebook;
|
|
ScreenR: TRect;
|
|
begin
|
|
DockSibling:='';
|
|
DockAlign:=alNone;
|
|
if (ObjectInspector1<>nil) and (aFormName=ObjectInspector1.Name) then begin
|
|
// place object inspector below main bar
|
|
ScreenR:=IDEWindowCreators.GetScreenrectForDefaults;
|
|
aBounds:=Rect(ScreenR.Left,
|
|
Min(MainIDEBar.Top+MainIDEBar.Height+25,200),230,
|
|
ScreenR.Bottom-ScreenR.Top-150);
|
|
// do not dock object inspector, because this would hide the floating designers
|
|
end
|
|
else if (aFormName=NonModalIDEWindowNames[nmiwMessagesViewName]) then begin
|
|
// place messages below source editor
|
|
ScreenR:=IDEWindowCreators.GetScreenrectForDefaults;
|
|
if SourceEditorManager.SourceWindowCount>0 then begin
|
|
SrcEditWnd:=SourceEditorManager.SourceWindows[0];
|
|
aBounds:=GetParentForm(SrcEditWnd).BoundsRect;
|
|
aBounds.Top:=aBounds.Bottom+25;
|
|
aBounds.Bottom:=aBounds.Top+100;
|
|
end else begin
|
|
aBounds:=Rect(ScreenR.Left+250,ScreenR.Bottom-200,ScreenR.Right-250,100);
|
|
end;
|
|
if IDEDockMaster<>nil then begin
|
|
DockSibling:=NonModalIDEWindowNames[nmiwSourceNoteBookName];
|
|
DockAlign:=alBottom;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.RenameInheritedMethods(AnUnitInfo: TUnitInfo; List: TStrings);
|
|
var
|
|
UsedByDependency: TUnitComponentDependency;
|
|
DependingUnit: TUnitInfo;
|
|
OldName: string;
|
|
NewName: string;
|
|
i: Integer;
|
|
begin
|
|
if List=nil then exit;
|
|
UsedByDependency:=AnUnitInfo.FirstUsedByComponent;
|
|
while UsedByDependency<>nil do begin
|
|
DependingUnit:=UsedByDependency.UsedByUnit;
|
|
if (DependingUnit.Component<>nil)
|
|
and (DependingUnit.Component.ClassParent=AnUnitInfo.Component.ClassType)
|
|
then begin
|
|
// the root component inherits from the DependingUnit root component
|
|
i:=0;
|
|
while i<List.Count-1 do begin
|
|
OldName:=List[i];
|
|
NewName:=List[i+1];
|
|
// replace references, ignoring errors
|
|
if CodeToolBoss.ReplaceWord(DependingUnit.Source,OldName,NewName,false)
|
|
then begin
|
|
// renamed in source, now rename in JIT class
|
|
FormEditor1.RenameJITMethod(DependingUnit.Component,
|
|
OldName,NewName);
|
|
end;
|
|
inc(i,2);
|
|
end;
|
|
ApplyCodeToolChanges;
|
|
// rename recursively
|
|
RenameInheritedMethods(DependingUnit,List);
|
|
end;
|
|
UsedByDependency:=UsedByDependency.NextUsedByDependency;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.OIHelpProvider: TAbstractIDEHTMLProvider;
|
|
var
|
|
HelpControl: TControl;
|
|
begin
|
|
if FOIHelpProvider = nil then
|
|
begin
|
|
HelpControl := CreateIDEHTMLControl(ObjectInspector1, FOIHelpProvider);
|
|
HelpControl.Parent := ObjectInspector1.InfoPanel;
|
|
HelpControl.Align := alClient;
|
|
HelpControl.BorderSpacing.Around := 2;
|
|
end;
|
|
Result := FOIHelpProvider;
|
|
end;
|
|
|
|
procedure TMainIDE.DoSwitchToFormSrc(var ActiveSourceEditor: TSourceEditor;
|
|
var ActiveUnitInfo: TUnitInfo);
|
|
begin
|
|
DoSwitchToFormSrc(nil,ActiveSourceEditor,ActiveUnitInfo);
|
|
end;
|
|
|
|
procedure TMainIDE.DoSwitchToFormSrc(ADesigner: TDesigner;
|
|
var ActiveSourceEditor: TSourceEditor; var ActiveUnitInfo: TUnitInfo);
|
|
begin
|
|
ActiveSourceEditor:=nil;
|
|
ActiveUnitInfo:=nil;
|
|
if (ADesigner<>nil) then
|
|
ActiveUnitInfo:=Project1.UnitWithComponent(ADesigner.LookupRoot)
|
|
else if (GlobalDesignHook.LookupRoot<>nil)
|
|
and (GlobalDesignHook.LookupRoot is TComponent) then
|
|
ActiveUnitInfo:=
|
|
Project1.UnitWithComponent(TComponent(GlobalDesignHook.LookupRoot))
|
|
else
|
|
ActiveUnitInfo:=nil;
|
|
if (ActiveUnitInfo<>nil) and (ActiveUnitInfo.OpenEditorInfoCount > 0) then begin
|
|
ActiveSourceEditor := TSourceEditor(ActiveUnitInfo.OpenEditorInfo[0].EditorComponent);
|
|
SourceEditorManagerIntf.ActiveEditor := ActiveSourceEditor;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.GetDesignerFormOfSource(AnUnitInfo: TUnitInfo; LoadForm: boolean
|
|
): TCustomForm;
|
|
begin
|
|
Result:=nil;
|
|
if AnUnitInfo.Component<>nil then
|
|
Result:=FormEditor1.GetDesignerForm(AnUnitInfo.Component);
|
|
if ((Result=nil) or (Result.Designer=nil)) and LoadForm
|
|
and FilenameIsPascalSource(AnUnitInfo.Filename) then begin
|
|
//DebugLn(['TMainIDE.GetFormOfSource ',AnUnitInfo.Filename,' ',dbgsName(AnUnitInfo.Component)]);
|
|
DoLoadLFM(AnUnitInfo,[],[]);
|
|
end;
|
|
if (Result=nil) and (AnUnitInfo.Component<>nil) then
|
|
Result:=FormEditor1.GetDesignerForm(AnUnitInfo.Component);
|
|
if (Result<>nil) and (Result.Designer=nil) then
|
|
Result:=nil;
|
|
end;
|
|
|
|
function TMainIDE.GetProjectFileWithRootComponent(AComponent: TComponent
|
|
): TLazProjectFile;
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
if AComponent=nil then exit(nil);
|
|
AnUnitInfo:=Project1.FirstUnitWithComponent;
|
|
while AnUnitInfo<>nil do begin
|
|
if AnUnitInfo.Component=AComponent then begin
|
|
Result:=AnUnitInfo;
|
|
exit;
|
|
end;
|
|
AnUnitInfo:=AnUnitInfo.NextUnitWithComponent;
|
|
end;
|
|
Result:=nil;
|
|
end;
|
|
|
|
function TMainIDE.GetProjectFileWithDesigner(ADesigner: TIDesigner
|
|
): TLazProjectFile;
|
|
var
|
|
TheDesigner: TDesigner;
|
|
AComponent: TComponent;
|
|
begin
|
|
TheDesigner:=ADesigner as TDesigner;
|
|
AComponent:=TheDesigner.LookupRoot;
|
|
if AComponent=nil then
|
|
RaiseException('TMainIDE.GetProjectFileWithDesigner Designer.LookupRoot=nil');
|
|
Result:=GetProjectFileWithRootComponent(AComponent);
|
|
end;
|
|
|
|
function TMainIDE.OnPropHookMethodExists(const AMethodName: String;
|
|
TypeData: PTypeData;
|
|
var MethodIsCompatible,MethodIsPublished,IdentIsMethod: boolean): boolean;
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[ctfSwitchToFormSource]) then
|
|
Exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
WriteLn('');
|
|
WriteLn('[TMainIDE.OnPropHookMethodExists] ************ ',AMethodName);
|
|
{$ENDIF}
|
|
Result := CodeToolBoss.PublishedMethodExists(ActiveUnitInfo.Source,
|
|
ActiveUnitInfo.Component.ClassName, AMethodName, TypeData,
|
|
MethodIsCompatible, MethodIsPublished, IdentIsMethod);
|
|
if CodeToolBoss.ErrorMessage <> '' then
|
|
begin
|
|
DoJumpToCodeToolBossError;
|
|
raise Exception.Create(lisUnableToFindMethod+' '+lisPleaseFixTheErrorInTheMessageWindow);
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.OnPropHookCreateMethod(const AMethodName: ShortString;
|
|
ATypeInfo: PTypeInfo;
|
|
APersistent: TPersistent; const APropertyPath: string): TMethod;
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
r: boolean;
|
|
OldChange: Boolean;
|
|
p: Integer;
|
|
APropName: String;
|
|
OldMethod: TMethod;
|
|
JITMethod: TJITMethod;
|
|
OverrideMethodName: String;
|
|
AComponent: TComponent;
|
|
begin
|
|
Result.Code:=nil;
|
|
Result.Data:=nil;
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[ctfSwitchToFormSource])
|
|
then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
debugln('');
|
|
debugln('[TMainIDE.OnPropHookCreateMethod] ************ ',AMethodName);
|
|
DebugLn(['[TMainIDE.OnPropHookCreateMethod] Persistent=',dbgsName(APersistent),' Unit=',GetClassUnitName(APersistent.ClassType),' Path=',APropertyPath]);
|
|
{$ENDIF}
|
|
|
|
OverrideMethodName:='';
|
|
if APersistent is TComponent then begin
|
|
AComponent:=TComponent(APersistent);
|
|
p:=length(APropertyPath);
|
|
while (p>0) and (APropertyPath[p]<>'.') do dec(p);
|
|
if p>0 then begin
|
|
APropName:=copy(APropertyPath,p+1,length(APropertyPath));
|
|
OldMethod:=GetMethodProp(APersistent,APropName);
|
|
if IsJITMethod(OldMethod) then begin
|
|
// there is an old method
|
|
JITMethod:=TJITMethod(OldMethod.Data);
|
|
if JITMethod.ClassType<>ActiveUnitInfo.Component.ClassType then begin
|
|
// the old method is inherited
|
|
// => search the component that has the method
|
|
//DebugLn(['TMainIDE.OnPropHookCreateMethod ',dbgsName(JITMethod.TheClass),' ',dbgsName(APersistent.ClassType),' ',dbgsName(APersistent)]);
|
|
while (AComponent<>nil)
|
|
and (not JITMethod.TheClass.InheritsFrom(AComponent.ClassType)) do
|
|
AComponent:=AComponent.Owner;
|
|
// create a path to the component
|
|
while (AComponent<>nil) and (AComponent<>ActiveUnitInfo.Component) do
|
|
begin
|
|
if OverrideMethodName<>'' then
|
|
OverrideMethodName:='.'+OverrideMethodName;
|
|
OverrideMethodName:=AComponent.Name+OverrideMethodName;
|
|
AComponent:=AComponent.Owner;
|
|
end;
|
|
if (AComponent=ActiveUnitInfo.Component)
|
|
and (OverrideMethodName<>'') then begin
|
|
// the old value does not belong to this main component, but to
|
|
// a nested/inline component
|
|
OverrideMethodName:=OverrideMethodName+'.'+JITMethod.TheMethodName;
|
|
DebugLn(['TMainIDE.OnPropHookCreateMethod OverrideMethodName=',OverrideMethodName]);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
OldChange:=OpenEditorsOnCodeToolChange;
|
|
OpenEditorsOnCodeToolChange:=true;
|
|
try
|
|
// create published method
|
|
r:=CodeToolBoss.CreatePublishedMethod(ActiveUnitInfo.Source,
|
|
ActiveUnitInfo.Component.ClassName,AMethodName,
|
|
ATypeInfo,false,GetClassUnitName(APersistent.ClassType),APropertyPath,
|
|
OverrideMethodName);
|
|
{$IFDEF IDE_DEBUG}
|
|
debugln('');
|
|
debugln('[TMainIDE.OnPropHookCreateMethod] ************2 ',dbgs(r),' ',AMethodName);
|
|
{$ENDIF}
|
|
ApplyCodeToolChanges;
|
|
if r then begin
|
|
Result:=FormEditor1.CreateNewJITMethod(ActiveUnitInfo.Component,
|
|
AMethodName);
|
|
end else begin
|
|
DebugLn(['TMainIDE.OnPropHookCreateMethod failed adding method to source']);
|
|
DoJumpToCodeToolBossError;
|
|
raise Exception.Create(lisUnableToCreateNewMethod+' '+lisPleaseFixTheErrorInTheMessageWindow);
|
|
end;
|
|
finally
|
|
OpenEditorsOnCodeToolChange:=OldChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnPropHookShowMethod(const AMethodName: String);
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
NewSource: TCodeBuffer;
|
|
NewX, NewY, NewTopLine: integer;
|
|
AClassName: string;
|
|
AInheritedMethodName: string;
|
|
AnInheritedClassName: string;
|
|
CurMethodName: String;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[ctfSwitchToFormSource])
|
|
then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
debugln('');
|
|
debugln('[TMainIDE.OnPropHookShowMethod] ************ "',AMethodName,'" ',ActiveUnitInfo.Filename);
|
|
{$ENDIF}
|
|
|
|
AClassName:=ActiveUnitInfo.Component.ClassName;
|
|
CurMethodName:=AMethodName;
|
|
|
|
if IsValidIdentPair(AMethodName,AnInheritedClassName,AInheritedMethodName)
|
|
then begin
|
|
ActiveSrcEdit:=nil;
|
|
ActiveUnitInfo:=Project1.UnitWithComponentClassName(AnInheritedClassName);
|
|
if ActiveUnitInfo=nil then begin
|
|
IDEMessageDialog(lisMethodClassNotFound,
|
|
Format(lisClassOfMethodNotFound, ['"', AnInheritedClassName, '"', '"',
|
|
AInheritedMethodName, '"']),
|
|
mtError,[mbCancel],'');
|
|
exit;
|
|
end;
|
|
AClassName:=AnInheritedClassName;
|
|
CurMethodName:=AInheritedMethodName;
|
|
end;
|
|
|
|
if CodeToolBoss.JumpToPublishedMethodBody(ActiveUnitInfo.Source,
|
|
AClassName,CurMethodName,
|
|
NewSource,NewX,NewY,NewTopLine) then
|
|
begin
|
|
DoJumpToCodePosition(ActiveSrcEdit, ActiveUnitInfo,
|
|
NewSource, NewX, NewY, NewTopLine, [jfAddJumpPoint, jfFocusEditor]);
|
|
end else begin
|
|
DebugLn(['TMainIDE.OnPropHookShowMethod failed finding the method in code']);
|
|
DoJumpToCodeToolBossError;
|
|
raise Exception.Create(lisUnableToShowMethod+' '+lisPleaseFixTheErrorInTheMessageWindow);
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnPropHookRenameMethod(const CurName, NewName: String);
|
|
var ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
BossResult: boolean;
|
|
ErrorMsg: String;
|
|
OldChange: Boolean;
|
|
RenamedMethods: TStringList;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[ctfSwitchToFormSource])
|
|
then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('');
|
|
writeln('[TMainIDE.OnPropHookRenameMethod] ************');
|
|
{$ENDIF}
|
|
OldChange:=OpenEditorsOnCodeToolChange;
|
|
OpenEditorsOnCodeToolChange:=true;
|
|
try
|
|
// rename/create published method
|
|
BossResult:=CodeToolBoss.RenamePublishedMethod(ActiveUnitInfo.Source,
|
|
ActiveUnitInfo.Component.ClassName,CurName,NewName);
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('');
|
|
writeln('[TMainIDE.OnPropHookRenameMethod] ************2 ');
|
|
{$ENDIF}
|
|
ApplyCodeToolChanges;
|
|
if BossResult then begin
|
|
FormEditor1.RenameJITMethod(ActiveUnitInfo.Component,CurName,NewName);
|
|
RenamedMethods:=TStringList.Create;
|
|
try
|
|
RenamedMethods.Add(CurName);
|
|
RenamedMethods.Add(NewName);
|
|
RenameInheritedMethods(ActiveUnitInfo,RenamedMethods);
|
|
finally
|
|
RenamedMethods.Free;
|
|
end;
|
|
end else begin
|
|
ErrorMsg:=CodeToolBoss.ErrorMessage;
|
|
DoJumpToCodeToolBossError;
|
|
raise Exception.Create(
|
|
lisUnableToRenameMethodPleaseFixTheErrorShownInTheMessag
|
|
+#13#13+lisError+ErrorMsg);
|
|
end;
|
|
finally
|
|
OpenEditorsOnCodeToolChange:=OldChange;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.OnPropHookBeforeAddPersistent(Sender: TObject;
|
|
APersistentClass: TPersistentClass; AParent: TPersistent): boolean;
|
|
begin
|
|
Result:=false;
|
|
if (not (AParent is TControl))
|
|
and (APersistentClass.InheritsFrom(TControl)) then begin
|
|
MessageDlg(lisCodeToolsDefsInvalidParent,
|
|
Format(lisACanNotHoldTControlsYouCanOnlyPutNonVisualComponen, [
|
|
AParent.ClassName, #13]),
|
|
mtError,[mbCancel],0);
|
|
UpdateIDEComponentPalette;
|
|
exit;
|
|
end;
|
|
Result:=true;
|
|
end;
|
|
|
|
procedure TMainIDE.OnPropHookComponentRenamed(AComponent: TComponent);
|
|
begin
|
|
FormEditor1.UpdateComponentName(AComponent);
|
|
end;
|
|
|
|
procedure TMainIDE.OnPropHookModified(Sender: TObject);
|
|
begin
|
|
// any change of property can cause a change of a display name
|
|
ObjectInspector1.FillPersistentComboBox;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
procedure TMainIDE.OnPropHookPersistentAdded(APersistent: TPersistent;
|
|
Select: boolean);
|
|
|
|
This handler is called whenever a new component was added to a designed form
|
|
and should be added to form source
|
|
-------------------------------------------------------------------------------}
|
|
procedure TMainIDE.OnPropHookPersistentAdded(APersistent: TPersistent; Select: boolean);
|
|
var
|
|
RegComp: TRegisteredComponent;
|
|
ADesigner: TDesigner;
|
|
AComponent: TComponent;
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
Ancestor: TComponent;
|
|
ComponentClassNames: TStringList;
|
|
ClassUnitInfo: TUnitInfo;
|
|
i: Integer;
|
|
begin
|
|
DebugLn('TMainIDE.OnPropHookPersistentAdded A ',dbgsName(APersistent));
|
|
ADesigner:=nil;
|
|
if APersistent is TComponent then
|
|
AComponent:=TComponent(APersistent)
|
|
else
|
|
AComponent:=nil;
|
|
RegComp:=IDEComponentPalette.FindComponent(APersistent.ClassName);
|
|
if (RegComp=nil) and (AComponent<>nil) then begin
|
|
ClassUnitInfo:=Project1.UnitWithComponentClass(TComponentClass(APersistent.ClassType));
|
|
if ClassUnitInfo=nil then begin
|
|
DebugLn('TMainIDE.OnPropHookPersistentAdded ',APersistent.ClassName,
|
|
' not registered');
|
|
exit;
|
|
end;
|
|
end;
|
|
if AComponent<>nil then begin
|
|
// create unique name
|
|
if AComponent.Name='' then
|
|
AComponent.Name:=FormEditor1.CreateUniqueComponentName(AComponent);
|
|
//writeln('TMainIDE.OnPropHookPersistentAdded B ',AComponent.Name,':',AComponent.ClassName);
|
|
// set component into design mode
|
|
SetDesigning(AComponent,true);
|
|
//writeln('TMainIDE.OnPropHookPersistentAdded C ',AComponent.Name,':',AComponent.ClassName);
|
|
// add to source
|
|
ADesigner:=FindRootDesigner(AComponent) as TDesigner;
|
|
end;
|
|
|
|
if (ADesigner<>nil) and ((RegComp<>nil) or (ClassUnitInfo<>nil)) then begin
|
|
if not BeginCodeTool(ADesigner,ActiveSrcEdit,ActiveUnitInfo,
|
|
[ctfSwitchToFormSource])
|
|
then exit;
|
|
|
|
// remember cursor position
|
|
SourceEditorManager.AddJumpPointClicked(Self);
|
|
|
|
// add needed package to required packages
|
|
if ADesigner.LookupRoot.ComponentCount>0 then
|
|
begin
|
|
ComponentClassNames:=TStringList.Create;
|
|
try
|
|
for i:=0 to ADesigner.LookupRoot.ComponentCount-1 do
|
|
ComponentClassNames.Add(ADesigner.LookupRoot.Components[i].ClassName);
|
|
//DebugLn(['TMainIDE.OnPropHookPersistentAdded ComponentClassNames=',ComponentClassNames.Text]);
|
|
PkgBoss.AddUnitDependenciesForComponentClasses(ActiveUnitInfo.Filename,
|
|
ComponentClassNames,true);
|
|
finally
|
|
ComponentClassNames.Free;
|
|
end;
|
|
end;
|
|
|
|
// add component definitions to form source
|
|
Ancestor:=GetAncestorLookupRoot(ActiveUnitInfo);
|
|
CodeToolBoss.CompleteComponent(ActiveUnitInfo.Source,ADesigner.LookupRoot,
|
|
Ancestor);
|
|
end;
|
|
|
|
ObjectInspector1.FillPersistentComboBox;
|
|
|
|
//writeln('TMainIDE.OnPropHookPersistentAdded D ',AComponent.Name,':',AComponent.ClassName,' ',Select);
|
|
// select component
|
|
if Select then begin
|
|
TheControlSelection.AssignPersistent(APersistent);
|
|
end;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TMainIDE.OnPropHookPersistentAdded END ',dbgsName(APersistent),' Select=',Select);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TMainIDE.OnPropHookDeletePersistent(var APersistent: TPersistent);
|
|
var
|
|
ADesigner: TDesigner;
|
|
AComponent: TComponent;
|
|
begin
|
|
if APersistent=nil then exit;
|
|
DebugLn('TMainIDE.OnPropHookDeletePersistent A ',dbgsName(APersistent));
|
|
if APersistent is TComponent then begin
|
|
AComponent:=TComponent(APersistent);
|
|
ADesigner:=TDesigner(FindRootDesigner(AComponent));
|
|
if ADesigner=nil then exit;
|
|
ADesigner.RemovePersistentAndChilds(AComponent);
|
|
end else begin
|
|
APersistent.Free;
|
|
end;
|
|
APersistent:=nil;
|
|
end;
|
|
|
|
procedure TMainIDE.OnPropHookObjectPropertyChanged(Sender: TObject;
|
|
NewObject: TPersistent);
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
NewComponent: TComponent;
|
|
ReferenceDesigner: TDesigner;
|
|
ReferenceUnitInfo: TUnitInfo;
|
|
begin
|
|
// check if a TPersistentPropertyEditor was changed
|
|
if not (Sender is TPersistentPropertyEditor) then exit;
|
|
if not (GlobalDesignHook.LookupRoot is TComponent) then exit;
|
|
// find the current unit
|
|
AnUnitInfo:=Project1.UnitWithComponent(TComponent(GlobalDesignHook.LookupRoot));
|
|
if AnUnitInfo=nil then begin
|
|
DebugLn(['TMainIDE.OnPropHookObjectPropertyChanged LookupRoot not found']);
|
|
exit;
|
|
end;
|
|
// find the reference unit
|
|
if (NewObject is TComponent) then begin
|
|
NewComponent:=TComponent(NewObject);
|
|
ReferenceDesigner:=TDesigner(FindRootDesigner(NewComponent));
|
|
if ReferenceDesigner=nil then exit;
|
|
ReferenceUnitInfo:=Project1.UnitWithComponent(ReferenceDesigner.LookupRoot);
|
|
if ReferenceUnitInfo=nil then begin
|
|
DebugLn(['TMainIDE.OnPropHookObjectPropertyChanged reference LookupRoot not found']);
|
|
exit;
|
|
end;
|
|
if ReferenceUnitInfo<>AnUnitInfo then begin
|
|
// another unit was referenced
|
|
// ToDo: add CreateForm statement to main unit (.lpr)
|
|
// At the moment the OI+PkgBoss only allow to use valid components,
|
|
// so the CreateForm already exists.
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.OnPropHookAddDependency(const AClass: TClass;
|
|
const AnUnitName: shortstring);
|
|
// add a package dependency to the package/project of the currently active
|
|
// designed component.
|
|
var
|
|
RequiredUnitName: String;
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
// check input
|
|
if AClass<>nil then begin
|
|
RequiredUnitName:=GetClassUnitName(AClass);
|
|
if (AnUnitName<>'')
|
|
and (SysUtils.CompareText(AnUnitName,RequiredUnitName)<>0) then
|
|
raise Exception.Create(
|
|
'TMainIDE.OnPropHookAddDependency unitname and class do not fit:'
|
|
+'unitname='+AnUnitName
|
|
+' class='+dbgs(AClass)+' class.unitname='+RequiredUnitName);
|
|
end else begin
|
|
RequiredUnitName:=AnUnitName;
|
|
end;
|
|
if RequiredUnitName='' then
|
|
raise Exception.Create('TMainIDE.OnPropHookAddDependency no unitname');
|
|
|
|
// find current designer and unit
|
|
if not (GlobalDesignHook.LookupRoot is TComponent) then exit;
|
|
AnUnitInfo:=Project1.UnitWithComponent(TComponent(GlobalDesignHook.LookupRoot));
|
|
if AnUnitInfo=nil then begin
|
|
DebugLn(['TMainIDE.OnPropHookAddDependency LookupRoot not found']);
|
|
exit;
|
|
end;
|
|
|
|
PkgBoss.AddDependencyToUnitOwners(AnUnitInfo.Filename,RequiredUnitName);
|
|
end;
|
|
|
|
procedure TMainIDE.OnPropHookGetComponentNames(TypeData: PTypeData;
|
|
Proc: TGetStrProc);
|
|
begin
|
|
PkgBoss.IterateComponentNames(GlobalDesignHook.LookupRoot,TypeData,Proc);
|
|
end;
|
|
|
|
function TMainIDE.OnPropHookGetComponent(const ComponentPath: String
|
|
): TComponent;
|
|
begin
|
|
Result:=PkgBoss.FindUsableComponent(GlobalDesignHook.LookupRoot,ComponentPath);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditCopyClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecCopy);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditCutClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecCut);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditPasteClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecPaste);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditRedoClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecRedo);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditUndoClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecUndo);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditIndentBlockClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecBlockIndent);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditUnindentBlockClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecBlockUnindent);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceEncloseBlockClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectionEnclose);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditUpperCaseBlockClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectionUpperCase);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditLowerCaseBlockClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectionLowerCase);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditSwapCaseBlockClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectionSwapCase);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditTabsToSpacesBlockClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectionTabs2Spaces);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceCommentBlockClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectionComment);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceUncommentBlockClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectionUncomment);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceToggleCommentClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecToggleComment);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceEncloseInIFDEFClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectionEncloseIFDEF);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditSortBlockClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectionSort);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditSelectionBreakLinesClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectionBreakLines);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditSelectAllClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectAll);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditSelectCodeBlockClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectCodeBlock);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditSelectToBraceClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectToBrace);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditSelectWordClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectWord);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditSelectLineClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectLine);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditSelectParagraphClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecSelectParagraph);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertGPLNoticeClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInsertGPLNotice);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertLGPLNoticeClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInsertLGPLNotice);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertModifiedLGPLNoticeClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInsertModifiedLGPLNotice);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertUsernameClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInsertUserName);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertDateTimeClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInsertDateTime);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertChangeLogEntryClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInsertChangeLogEntry);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertGUID(Sender: TObject);
|
|
begin
|
|
DoInsertGUID;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertFilename(Sender: TObject);
|
|
begin
|
|
DoInsertFilename;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSearchFindInFiles(Sender: TObject);
|
|
begin
|
|
DoFindInFiles;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSearchFindIdentifierRefsClicked(Sender: TObject);
|
|
begin
|
|
DoFindRenameIdentifier(false);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuEditInsertCharacterClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInsertCharacter);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertCVSAuthorClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInsertCVSAuthor);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertCVSDateClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInsertCVSDate);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertCVSHeaderClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInsertCVSHeader);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertCVSIDClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInsertCVSID);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertCVSLogClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInsertCVSLog);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertCVSNameClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInsertCVSName);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertCVSRevisionClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInsertCVSRevision);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceInsertCVSSourceClick(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInsertCVSSource);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceCompleteCodeClicked(Sender: TObject);
|
|
begin
|
|
DoCompleteCodeAtCursor;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSourceUseUnitClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecUseUnit);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuRefactorRenameIdentifierClicked(Sender: TObject);
|
|
begin
|
|
DoFindRenameIdentifier(true);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuRefactorExtractProcClicked(Sender: TObject);
|
|
begin
|
|
DoExtractProcFromSelection;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuRefactorInvertAssignmentClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecInvertAssignment);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuRefactorShowAbstractMethodsClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecShowAbstractMethods);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuRefactorShowEmptyMethodsClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecRemoveEmptyMethods);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuRefactorShowUnusedUnitsClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecRemoveUnusedUnits);
|
|
end;
|
|
|
|
procedure TMainIDE.mnuRefactorFindOverloadsClicked(Sender: TObject);
|
|
begin
|
|
DoSourceEditorCommand(ecFindOverloads);
|
|
end;
|
|
|
|
procedure TMainIDE.DoCommand(ACommand: integer);
|
|
var
|
|
ActiveSourceEditor: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
AForm: TCustomForm;
|
|
begin
|
|
// todo: if focus is really on a designer or the source editor
|
|
GetCurrentUnit(ActiveSourceEditor,ActiveUnitInfo);
|
|
case FDisplayState of
|
|
dsSource: // send command to source editor
|
|
if Assigned(ActiveSourceEditor) then
|
|
ActiveSourceEditor.DoEditorExecuteCommand(ACommand);
|
|
dsForm: // send command to form editor
|
|
begin
|
|
if FLastFormActivated <> nil then
|
|
GetUnitWithForm(FLastFormActivated, ActiveSourceEditor, ActiveUnitInfo);
|
|
if Assigned(ActiveUnitInfo) then begin
|
|
AForm:=GetDesignerFormOfSource(ActiveUnitInfo,False);
|
|
if AForm<>nil then ;
|
|
// ToDo: call designer
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMainIDE.DoSourceEditorCommand(EditorCommand: integer);
|
|
var
|
|
CurFocusControl: TWinControl;
|
|
begin
|
|
// check that the currently focus is on the MainIDEBar or on the SourceEditor
|
|
CurFocusControl:=FindOwnerControl(GetFocus);
|
|
if (CurFocusControl<>nil) then begin
|
|
CurFocusControl:=GetParentForm(CurFocusControl);
|
|
if (CurFocusControl<>MainIDEBar) and not(CurFocusControl is TSourceNotebook) then
|
|
begin
|
|
// continue processing shortcut, not handled yet
|
|
MainIDEBar.mnuMainMenu.ShortcutHandled := false;
|
|
exit;
|
|
end;
|
|
end;
|
|
DoCommand(EditorCommand);
|
|
end;
|
|
|
|
procedure TMainIDE.DoInsertGUID;
|
|
const
|
|
cGUID = '[''%s'']'; // The format of the GUID used for Interfaces
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
lGUID: TGUID;
|
|
begin
|
|
// get active source editor
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
if ActiveSrcEdit = nil then Exit;
|
|
|
|
CreateGUID(lGUID);
|
|
ActiveSrcEdit.Selection := Format(cGUID, [GUIDToString(lGUID)]);
|
|
end;
|
|
|
|
procedure TMainIDE.DoInsertFilename;
|
|
var
|
|
ActiveSrcEdit: TSourceEditor;
|
|
ActiveUnitInfo: TUnitInfo;
|
|
begin
|
|
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
|
|
if ActiveSrcEdit = nil then Exit;
|
|
with TOpenDialog.Create(nil) do
|
|
try
|
|
if Execute then
|
|
ActiveSrcEdit.Selection := FileName;
|
|
finally
|
|
Free;
|
|
end;
|
|
end;
|
|
|
|
function TMainIDE.DoReplaceUnitUse(OldFilename, OldUnitName, NewFilename,
|
|
NewUnitName: string; IgnoreErrors, Quiet, Confirm: boolean): TModalResult;
|
|
{ Replaces all references to a unit
|
|
|
|
}
|
|
var
|
|
OwnerList: TFPList;
|
|
ExtraFiles: TStrings;
|
|
Files: TStringList;
|
|
OldCode: TCodeBuffer;
|
|
OldCodeCreated: Boolean;
|
|
PascalReferences: TAVLTree;
|
|
i: Integer;
|
|
MsgResult: TModalResult;
|
|
begin
|
|
if (CompareFilenames(OldFilename,NewFilename)=0)
|
|
and (OldUnitName=NewUnitName) then // compare unitnames case sensitive, maybe only the case changed
|
|
exit(mrOk);
|
|
|
|
OwnerList:=nil;
|
|
OldCode:=nil;
|
|
OldCodeCreated:=false;
|
|
PascalReferences:=nil;
|
|
Files:=TStringList.Create;
|
|
try
|
|
// get owners of unit
|
|
OwnerList:=PkgBoss.GetOwnersOfUnit(NewFilename);
|
|
if OwnerList=nil then exit(mrOk);
|
|
PkgBoss.ExtendOwnerListWithUsedByOwners(OwnerList);
|
|
ReverseList(OwnerList);
|
|
|
|
// get source files of packages and projects
|
|
ExtraFiles:=PkgBoss.GetSourceFilesOfOwners(OwnerList);
|
|
try
|
|
if ExtraFiles<>nil then
|
|
Files.AddStrings(ExtraFiles);
|
|
finally
|
|
ExtraFiles.Free;
|
|
end;
|
|
for i:=Files.Count-1 downto 0 do begin
|
|
if (CompareFilenames(Files[i],OldFilename)=0)
|
|
or (CompareFilenames(Files[i],NewFilename)=0) then
|
|
Files.Delete(i);
|
|
end;
|
|
|
|
//DebugLn(['TMainIDE.DoReplaceUnitUse ',Files.Text]);
|
|
|
|
// commit source editor to codetools
|
|
SaveSourceEditorChangesToCodeCache(nil);
|
|
|
|
// load or create old unit
|
|
OldCode:=CodeToolBoss.LoadFile(OldFilename,true,false);
|
|
if OldCode=nil then begin
|
|
// create old file in memory so that unit search can find it
|
|
OldCode:=CodeToolBoss.CreateFile(OldFilename);
|
|
OldCodeCreated:=true;
|
|
end;
|
|
|
|
// search pascal source references
|
|
Result:=GatherUnitReferences(Files,OldCode,false,IgnoreErrors,true,
|
|
PascalReferences);
|
|
if (not IgnoreErrors) and (not Quiet) and (CodeToolBoss.ErrorMessage<>'')
|
|
then
|
|
DoJumpToCodeToolBossError;
|
|
if Result<>mrOk then begin
|
|
debugln('TMainIDE.DoReplaceUnitUse GatherUnitReferences failed');
|
|
exit;
|
|
end;
|
|
|
|
// replace
|
|
if (PascalReferences<>nil) and (PascalReferences.Count>0) then begin
|
|
if Confirm then begin
|
|
MsgResult:=IDEQuestionDialog(lisUpdateReferences,
|
|
Format(lisTheUnitIsUsedByOtherFilesUpdateReferencesAutomatic, [
|
|
OldUnitName, #13]), mtConfirmation,
|
|
[mrYes,mrNo,mrYesToAll,mrNoToAll],'');
|
|
case MsgResult of
|
|
mrYes: ;
|
|
mrYesToAll: EnvironmentOptions.UnitRenameReferencesAction:=urraAlways;
|
|
mrNoToAll:
|
|
begin
|
|
EnvironmentOptions.UnitRenameReferencesAction:=urraNever;
|
|
Result:=mrOk;
|
|
exit;
|
|
end;
|
|
else
|
|
Result:=mrOk;
|
|
exit;
|
|
end;
|
|
end;
|
|
if not CodeToolBoss.RenameIdentifier(PascalReferences,
|
|
OldUnitName,NewUnitName)
|
|
then begin
|
|
if (not IgnoreErrors) and (not Quiet) then
|
|
DoJumpToCodeToolBossError;
|
|
debugln('TMainIDE.DoReplaceUnitUse unable to commit');
|
|
if not IgnoreErrors then begin
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
finally
|
|
if OldCodeCreated then
|
|
OldCode.IsDeleted:=true;
|
|
CodeToolBoss.FreeTreeOfPCodeXYPosition(PascalReferences);
|
|
OwnerList.Free;
|
|
Files.Free;
|
|
end;
|
|
//PkgBoss.GetOwnersOfUnit(NewFilename);
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
procedure TMainIDE.AddRecentProjectFileToEnvironment(const AFilename: string);
|
|
begin
|
|
EnvironmentOptions.AddToRecentProjectFiles(AFilename);
|
|
SetRecentProjectFilesMenu;
|
|
SaveEnvironment;
|
|
end;
|
|
|
|
procedure TMainIDE.StartProtocol;
|
|
begin
|
|
IDEProtocolOpts:=TIDEProtocol.Create;
|
|
IDEProtocolOpts.Load;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSearchFindBlockOtherEnd(Sender: TObject);
|
|
begin
|
|
DoGoToPascalBlockOtherEnd;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSearchFindBlockStart(Sender: TObject);
|
|
begin
|
|
DoGoToPascalBlockStart;
|
|
end;
|
|
|
|
procedure TMainIDE.mnuSearchFindDeclaration(Sender: TObject);
|
|
begin
|
|
DoFindDeclarationAtCursor;
|
|
end;
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
initialization
|
|
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('main.pp: initialization');{$ENDIF}
|
|
{$I ../images/laz_images.lrs}
|
|
// we have a bundle icon, don't use low quality standard icon
|
|
ShowSplashScreen:=true;
|
|
end.
|
|
|
|
|