IDE: Improve the desktops feature. Prevent access violation and exception. Store z-order of windows. Patch from Ondrej Pokorny.

git-svn-id: trunk@49525 -
This commit is contained in:
juha 2015-07-11 23:27:44 +00:00
parent c783e32fb3
commit 4f0f211f3c
7 changed files with 196 additions and 78 deletions

View File

@ -282,11 +282,12 @@ type
procedure StoreWindowPositions;
procedure SetDefaultPosition(const AForm: TCustomForm);
procedure Assign(SrcList: TSimpleWindowLayoutList; AssignOnlyNewlyCreated,
DestroyNotAssigned: Boolean);
DestroyNotAssigned, AssignOrder: Boolean);
function Add(ALayout: TSimpleWindowLayout): integer;
function CreateWindowLayout(const TheFormID: string): TSimpleWindowLayout;
function CreateWindowLayout(const TheForm: TCustomForm): TSimpleWindowLayout;
function IndexOf(const FormID: string): integer;
function IndexOf(const AForm: TCustomForm): integer;
function ItemByForm(AForm: TCustomForm): TSimpleWindowLayout;
function ItemByFormID(const FormID: string): TSimpleWindowLayout;
function ItemByFormCaption(const aFormCaption: string): TSimpleWindowLayout;
@ -1502,11 +1503,18 @@ begin
while (Result>=0) and (FormID<>Items[Result].GetFormID) do dec(Result);
end;
function TSimpleWindowLayoutList.IndexOf(const AForm: TCustomForm): integer;
begin
Result:=Count-1;
while (Result>=0) and (AForm<>Items[Result].Form) do dec(Result);
end;
procedure TSimpleWindowLayoutList.LoadFromConfig(Config: TConfigStorage; const Path: string);
// do not clear, just add/replace the values from the config
var
i: integer;
ID: String;
xLayoutIndex: Integer;
begin
// create new windows
i := Config.GetValue(Path+'Desktop/FormIdCount', 0);
@ -1514,9 +1522,16 @@ begin
while i > 0 do begin
ID := Config.GetValue(Path+'Desktop/FormIdList/a'+IntToStr(i), '');
//debugln(['TSimpleWindowLayoutList.LoadFromConfig ',i,' ',ID]);
if (ID <> '') and IsValidIdent(ID)
and (IDEWindowCreators.SimpleLayoutStorage.ItemByFormID(ID) = nil) then
CreateWindowLayout(ID);
if (ID <> '') and IsValidIdent(ID) then
begin
xLayoutIndex := IndexOf(ID);
if (xLayoutIndex = -1) then
begin
CreateWindowLayout(ID);
xLayoutIndex := Count-1;
end;
fItems.Move(xLayoutIndex, 0);
end;
dec(i);
end;
@ -1557,13 +1572,11 @@ function TSimpleWindowLayoutList.ItemByForm(AForm: TCustomForm): TSimpleWindowLa
var
i: integer;
begin
i:=Count-1;
while (i>=0) do begin
Result:=Items[i];
if Result.Form=AForm then exit;
dec(i);
end;
Result:=nil;
i:=IndexOf(AForm);
if i>=0 then
Result:=Items[i]
else
Result:=nil;
end;
function TSimpleWindowLayoutList.ItemByFormID(const FormID: string): TSimpleWindowLayout;
@ -1755,14 +1768,25 @@ begin
end;
procedure TSimpleWindowLayoutList.StoreWindowPositions;
var i: integer;
var
i, l: integer;
xOldLayoutIndex: Integer;
begin
//store positions
for i:=0 to Count-1 do
Items[i].GetCurrentPosition;
//store z-order
for i:=Screen.CustomFormCount-1 downto 0 do
begin
xOldLayoutIndex := IndexOf(Screen.CustomForms[i]);
if xOldLayoutIndex > 0 then
fItems.Move(xOldLayoutIndex, 0);
end;
end;
procedure TSimpleWindowLayoutList.Assign(SrcList: TSimpleWindowLayoutList;
AssignOnlyNewlyCreated, DestroyNotAssigned: Boolean);
AssignOnlyNewlyCreated, DestroyNotAssigned, AssignOrder: Boolean);
var
i: integer;
xItemIndex: Integer;
@ -1779,19 +1803,25 @@ begin
xItemIndex := Self.Add(TSimpleWindowLayout.Create(SrcList[i].FormID));//not found, create
xNewlyCreated := True;
end;
if xItemIndex<>i then
if (xItemIndex<>i) and (AssignOrder) then
begin
Self.fItems.Move(xItemIndex, i);//move it to right position
xItemIndex := i;
end;
end else
xItemIndex := i;
end;
if not AssignOnlyNewlyCreated or xNewlyCreated then
Self.Items[i].Assign(SrcList[i])
Self.Items[xItemIndex].Assign(SrcList[i])
end;
for i := Count-1 downto xItemIndex+1 do
for i := Count-1 downto 0 do
if SrcList.IndexOf(Items[i].FormID) = -1 then
begin
if DestroyNotAssigned then
Delete(i)
else
Items[i].Clear;
end;
end;
function TSimpleWindowLayoutList.Add(ALayout: TSimpleWindowLayout): integer;
@ -2206,19 +2236,16 @@ var
begin
if IDEDockMaster=nil then
begin
for i:=0 to SimpleLayoutStorage.Count-1 do begin
for i:=SimpleLayoutStorage.Count-1 downto 0 do//loop down in order to keep z-order of the forms
begin
ALayout:=SimpleLayoutStorage[i];
AForm:=GetForm(ALayout.FormID,ALayout.Visible);
if AForm=nil then Continue;
ALayout.Apply(True);
if ALayout.Visible then
ShowForm(AForm,false)
else
begin
//ALayout.Apply;
if AForm.Visible then
AForm.Close;
end;
if ALayout.Visible or (AForm=Application.MainForm) then
ShowForm(AForm,true)
else if AForm.Visible then
AForm.Close;
end;
end;
LayoutChanged;

View File

@ -15,10 +15,10 @@ object DesktopForm: TDesktopForm
AnchorSideTop.Control = DesktopListBox
AnchorSideRight.Control = DeleteBitBtn
AnchorSideRight.Side = asrBottom
Left = 237
Left = 280
Height = 23
Top = 14
Width = 189
Width = 146
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Top = 6
Caption = 'Save current desktop'
@ -40,7 +40,7 @@ object DesktopForm: TDesktopForm
CancelButton.Name = 'CancelButton'
CancelButton.Caption = 'Close'
CancelButton.DefaultCaption = False
TabOrder = 4
TabOrder = 5
ShowButtons = [pbOK, pbCancel]
ShowGlyphs = [pbOK, pbClose, pbHelp]
end
@ -49,7 +49,7 @@ object DesktopForm: TDesktopForm
Left = 11
Height = 147
Top = 8
Width = 216
Width = 259
Anchors = [akTop, akLeft, akRight, akBottom]
BorderSpacing.Right = 10
ItemHeight = 0
@ -62,33 +62,61 @@ object DesktopForm: TDesktopForm
end
object DeleteBitBtn: TBitBtn
AnchorSideLeft.Control = SetDebugDesktopBitBtn
AnchorSideTop.Control = SaveBitBtn
AnchorSideTop.Control = RenameBitBtn
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = SetDebugDesktopBitBtn
AnchorSideRight.Side = asrBottom
Left = 237
Left = 280
Height = 23
Top = 43
Width = 189
Top = 120
Width = 146
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Top = 6
Caption = 'Delete selected desktop'
BorderSpacing.Top = 4
Caption = 'Delete'
OnClick = DeleteBitBtnClick
TabOrder = 2
TabOrder = 4
end
object SetDebugDesktopBitBtn: TBitBtn
AnchorSideTop.Control = DeleteBitBtn
AnchorSideTop.Control = SelectedDesktopLabel
AnchorSideTop.Side = asrBottom
AnchorSideRight.Side = asrBottom
Left = 237
Left = 280
Height = 23
Top = 86
Width = 189
Top = 66
Width = 146
Anchors = [akTop, akRight]
AutoSize = True
BorderSpacing.Top = 20
Caption = 'Toggle selected as debug desktop'
BorderSpacing.Top = 6
Caption = 'Toggle as debug desktop'
OnClick = SetDebugDesktopBitBtnClick
TabOrder = 2
end
object SelectedDesktopLabel: TLabel
AnchorSideLeft.Control = SaveBitBtn
AnchorSideTop.Control = SaveBitBtn
AnchorSideTop.Side = asrBottom
Left = 280
Height = 13
Top = 47
Width = 86
BorderSpacing.Top = 10
Caption = 'Selected desktop:'
ParentColor = False
end
object RenameBitBtn: TBitBtn
AnchorSideLeft.Control = SetDebugDesktopBitBtn
AnchorSideTop.Control = SetDebugDesktopBitBtn
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = SetDebugDesktopBitBtn
AnchorSideRight.Side = asrBottom
Left = 280
Height = 23
Top = 93
Width = 146
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Top = 4
Caption = 'Rename'
OnClick = RenameBitBtnClick
TabOrder = 3
end
end

View File

@ -15,6 +15,8 @@ type
TDesktopForm = class(TForm)
ButtonPanel1: TButtonPanel;
RenameBitBtn: TBitBtn;
SelectedDesktopLabel: TLabel;
SetDebugDesktopBitBtn: TBitBtn;
DesktopListBox: TListBox;
SaveBitBtn: TBitBtn;
@ -22,10 +24,11 @@ type
procedure DeleteBitBtnClick(Sender: TObject);
procedure DesktopListBoxDblClick(Sender: TObject);
procedure DesktopListBoxDrawItem(Control: TWinControl; Index: Integer;
ARect: TRect; State: TOwnerDrawState);
ARect: TRect; {%H-}State: TOwnerDrawState);
procedure DesktopListBoxKeyPress(Sender: TObject; var Key: char);
procedure DesktopListBoxSelectionChange(Sender: TObject; {%H-}User: boolean);
procedure FormCreate(Sender: TObject);
procedure RenameBitBtnClick(Sender: TObject);
procedure SaveBitBtnClick(Sender: TObject);
procedure SetDebugDesktopBitBtnClick(Sender: TObject);
private
@ -78,10 +81,13 @@ begin
// buttons captions & text
Caption := dlgManageDesktops;
SelectedDesktopLabel.Caption := dlgSelectedDesktop;
SaveBitBtn.Caption := dlgSaveCurrentDesktop;
SaveBitBtn.LoadGlyphFromResourceName(HInstance, 'laz_save');
DeleteBitBtn.Caption := dlgDeleteSelectedDesktop;
DeleteBitBtn.Caption := lisDelete;
DeleteBitBtn.LoadGlyphFromResourceName(HInstance, 'laz_delete');
RenameBitBtn.Caption := lisRename;
RenameBitBtn.LoadGlyphFromResourceName(HInstance, 'laz_edit');
SetDebugDesktopBitBtn.Caption := dlgToggleSelectedDebugDesktop;
SetDebugDesktopBitBtn.LoadGlyphFromResourceName(HInstance, 'menu_run');
ButtonPanel1.OKButton.Caption := dlgCloseAndUseSelectedDesktop;
@ -98,10 +104,48 @@ begin
for i:=0 to Desktops.Count-1 do
DesktopListBox.Items.Add(Desktops[i].Name);
DesktopListBox.ItemIndex := DesktopListBox.Items.IndexOf(SelectName);
i := DesktopListBox.Items.IndexOf(SelectName);
if (i < 0) and (DesktopListBox.Count > 0) then
i := 0;
DesktopListBox.ItemIndex := i;
DesktopListBoxSelectionChange(DesktopListBox, False);
end;
procedure TDesktopForm.RenameBitBtnClick(Sender: TObject);
var
xDesktopName, xOldDesktopName: String;
dskIndex: Integer;
begin
if DesktopListBox.ItemIndex = -1 then
Exit;
xDesktopName := DesktopListBox.Items[DesktopListBox.ItemIndex];
xOldDesktopName := xDesktopName;
if not InputQuery(dlgRenameDesktop, dlgDesktopName, xDesktopName)
or (xDesktopName = '') // xDesktopName MUST NOT BE EMPTY !!!
or (xDesktopName = xOldDesktopName)
then
Exit;
with EnvironmentOptions do
begin
dskIndex := Desktops.IndexOf(xDesktopName);//delete old entry in list if new name is present
if (dskIndex >= 0) then
begin
if (MessageDlg(Format(dlgOverwriteDesktop, [xDesktopName]), mtWarning, mbYesNo, 0) = mrYes) then
Desktops.Delete(dskIndex)
else
Exit;
end;
dskIndex := Desktops.IndexOf(xOldDesktopName);//rename
Desktops[dskIndex].Name := xDesktopName;
RefreshList(xDesktopName);
end;
end;
procedure TDesktopForm.DeleteBitBtnClick(Sender: TObject);
var
xDesktopName: String;
@ -198,6 +242,7 @@ procedure TDesktopForm.DesktopListBoxSelectionChange(Sender: TObject;
User: boolean);
begin
DeleteBitBtn.Enabled := DesktopListBox.ItemIndex>=0;
RenameBitBtn.Enabled := DeleteBitBtn.Enabled;
SetDebugDesktopBitBtn.Enabled := DeleteBitBtn.Enabled;
ButtonPanel1.OKButton.Enabled := DeleteBitBtn.Enabled;
end;
@ -205,14 +250,15 @@ end;
procedure TDesktopForm.SaveBitBtnClick(Sender: TObject);
var
dsk: TDesktopOpt;
xDesktopName: string;
xDesktopName, xOldDesktopName: string;
begin
if DesktopListBox.ItemIndex >= 0 then
xDesktopName := DesktopListBox.Items[DesktopListBox.ItemIndex]
else
xDesktopName := '';
xOldDesktopName := xDesktopName;
if not InputQuery(dlgSaveCurrentDesktop, dlgDesktopNameWillBeOverwritten, xDesktopName)
if not InputQuery(dlgSaveCurrentDesktop, dlgDesktopName, xDesktopName)
or (xDesktopName = '') // xDesktopName MUST NOT BE EMPTY !!!
then
Exit;
@ -220,6 +266,12 @@ begin
with EnvironmentOptions do
begin
dsk := Desktops.Find(xDesktopName);
if Assigned(dsk) and
(xOldDesktopName <> xDesktopName) and//ask only if manually inserted
(MessageDlg(Format(dlgOverwriteDesktop, [xDesktopName]), mtWarning, mbYesNo, 0) <> mrYes)
then
Exit;
if not Assigned(dsk) then
begin
debugln(['TDesktopForm.SaveBitBtnClick: Adding ', xDesktopName]);

View File

@ -979,7 +979,7 @@ begin
FIDEDialogLayoutList:=TIDEDialogLayoutList.Create;
FIDEWindowCreatorsLayoutList:=TSimpleWindowLayoutList.Create(False);
FIDEDialogLayoutList.Assign(IDEWindowIntf.IDEDialogLayoutList);
FIDEWindowCreatorsLayoutList.Assign(IDEWindowIntf.IDEWindowCreators.SimpleLayoutStorage, True, True);
FIDEWindowCreatorsLayoutList.Assign(IDEWindowIntf.IDEWindowCreators.SimpleLayoutStorage, True, True, True);
end;
end;
@ -1007,8 +1007,8 @@ begin
// window layout
if Source.FIDEWindowCreatorsLayoutList <> IDEWindowCreators.SimpleLayoutStorage then
Source.FIDEWindowCreatorsLayoutList.Assign(IDEWindowCreators.SimpleLayoutStorage, True, True);
FIDEWindowCreatorsLayoutList.Assign(Source.FIDEWindowCreatorsLayoutList, False, False);
Source.FIDEWindowCreatorsLayoutList.Assign(IDEWindowCreators.SimpleLayoutStorage, True, True, False);
FIDEWindowCreatorsLayoutList.Assign(Source.FIDEWindowCreatorsLayoutList, False, False, True);
FIDEDialogLayoutList.Assign(Source.FIDEDialogLayoutList);
FSingleTaskBarButton := Source.FSingleTaskBarButton;
FHideIDEOnRun := Source.FHideIDEOnRun;
@ -2316,33 +2316,40 @@ begin
end;
procedure TEnvironmentOptions.UseDesktop(ADesktop: TDesktopOpt);
procedure _UpdateEditorOptions(const aAfter: Boolean);
function _ContainsControl(const _Parent, _Control: TWinControl): Boolean;
var
i: Integer;
Rec: PIDEOptionsGroupRec;
Instance: TAbstractIDEOptions;
I: Integer;
begin
for i := 0 to IDEEditorGroups.Count - 1 do
for I := 0 to _Parent.ControlCount-1 do
if _Parent.Controls[I] is TWinControl then
begin
Rec := IDEEditorGroups[i];
if Assigned(Rec^.Items) and Assigned(Rec^.GroupClass) then
begin
Instance := Rec^.GroupClass.GetInstance;
if Assigned(Instance) then
begin
if aAfter then
Instance.DoAfterWrite(False)
else
Instance.DoBeforeWrite(False)
end;
end;
if (_Parent.Controls[I] = _Control) or
_ContainsControl(TWinControl(_Parent.Controls[I]), _Control)
then
Exit(True);
end;
Result := False;
end;
var
xLastFocusControl: TWinControl;
xLastFocusForm: TCustomForm;
begin
_UpdateEditorOptions(False);
xLastFocusControl := Screen.ActiveControl;
xLastFocusForm := Screen.ActiveCustomForm;
DoBeforeWrite(False);
Desktop.Assign(ADesktop);
_UpdateEditorOptions(True);
DoAfterWrite(False);
IDEWindowCreators.RestoreSimpleLayout;
//set focus back to the previously focused control
if Screen.CustomFormIndex(xLastFocusForm) >= 0 then//check if form hasn't been destroyed
begin
if ((xLastFocusForm = xLastFocusControl) or _ContainsControl(xLastFocusForm, xLastFocusControl)) and//check if control hasn't been destroyed
xLastFocusForm.CanFocus and
xLastFocusControl.CanFocus
then
xLastFocusControl.SetFocus;
end;
end;
procedure TEnvironmentOptions.SetLazarusDirectory(const AValue: string);

View File

@ -150,7 +150,7 @@ begin
ProjectDirInIdeTitleCheckBox.Checked:=IDEProjectDirectoryInIdeTitle;
end;
FLayouts.Assign(IDEWindowCreators.SimpleLayoutStorage, False, True);
FLayouts.Assign(IDEWindowCreators.SimpleLayoutStorage, False, True, True);
if FShowSimpleLayout then begin
// Window Positions
@ -217,8 +217,8 @@ end;
procedure TWindowOptionsFrame.WriteSettings(AOptions: TAbstractIDEOptions);
begin
SaveLayout;
FLayouts.Assign(IDEWindowCreators.SimpleLayoutStorage, True, True);
IDEWindowCreators.SimpleLayoutStorage.Assign(FLayouts, False, False);
FLayouts.Assign(IDEWindowCreators.SimpleLayoutStorage, True, True, False);
IDEWindowCreators.SimpleLayoutStorage.Assign(FLayouts, False, False, True);
with (AOptions as TEnvironmentOptions).Desktop do
begin

View File

@ -1235,12 +1235,14 @@ resourcestring
dlgExportDesktop = 'Export desktop';
dlgImportDesktop = 'Import desktop';
dlgManageDesktops = 'Manage desktops';
dlgSelectedDesktop = 'Selected desktop:';
dlgSaveCurrentDesktop = 'Save current desktop';
dlgCloseAndUseSelectedDesktop = 'Close and use selected desktop';
dlgDeleteSelectedDesktop = 'Delete selected desktop';
dlgReallyDeleteDesktop = 'Really delete desktop "%s"?';
dlgToggleSelectedDebugDesktop = 'Toggle selected as debug desktop';
dlgDesktopNameWillBeOverwritten = 'Desktop name (old entry will be overwritten):';
dlgRenameDesktop = 'Rename desktop';
dlgToggleSelectedDebugDesktop = 'Toggle as debug desktop';
dlgDesktopName = 'Desktop name:';
dlgOverwriteDesktop = 'Desktop with the name "%s" was found.'+sLineBreak+'Should the old desktop be overwritten?';
dlgDebugDesktop = 'debug desktop';
dlgDesktopHints = 'Hints';
dlgDesktopButtons = 'Buttons - ';

View File

@ -8221,9 +8221,11 @@ begin
end else if State=iwgfDisabled then
SearchResultsView.DisableAutoSizing;
if State>=iwgfShow then
begin
IDEWindowCreators.ShowForm(SearchresultsView,State=iwgfShowOnTop);
if SearchresultsView.SearchInListEdit.CanFocus then
SearchresultsView.SearchInListEdit.SetFocus;
if (State=iwgfShowOnTop) and SearchresultsView.SearchInListEdit.CanFocus then
SearchresultsView.SearchInListEdit.SetFocus;
end;
end;
function TMainIDE.GetTestBuildDirectory: string;