Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making Source writable from the Delphi IDE

Tags:

ide

delphi

Is it possible to make readonly source code (eg., .pas & .dfm) writable from within the Delphi IDE? The right click option to make files Readonly/Writable within the IDE doesn't change the properties on the file system. Is there an IDE extension or similar that can achieve this?

A way to do this without having to integrate a source control system would be preferable. I am using Delphi XE and Delphi 6.

Thanks!

sse

like image 550
sse Avatar asked Dec 19 '11 13:12

sse


2 Answers

This is how I would do it.

Create a new package which will be installed into the IDE at designtime. If you have an existing package handy then you could carry on using it. Make sure the package requires the designide package. You can do this in the project manager, or just by viewing the project source and adding designide to the requires clause.

Now add the following unit to your package.

unit MakeEditable;

interface

procedure Register;

implementation

uses
  Windows, SysUtils, Menus, ToolsAPI;

type
  TMakeEditable = class(TObject)
  private
    FEditorServices: IOTAEditorServices;
    FFileMenu: TMenuItem;
    FMakeEditable: TMenuItem;
    function MenuItemWithCaptionLike(const Menu: TMenuItem; const DesiredCaption: string): TMenuItem;
    procedure MakeEditableClick(Sender: TObject);
  public
    constructor Create;
    destructor Destroy; override;
  end;

constructor TMakeEditable.Create;
var
  Index: Integer;
  PreviousMenuItem: TMenuItem;
begin
  inherited;
  FEditorServices := (BorlandIDEServices as IOTAEditorServices);
  FFileMenu := MenuItemWithCaptionLike((BorlandIDEServices as INTAServices40).MainMenu.Items, 'File');
  if Assigned(FFileMenu) then begin
    PreviousMenuItem := MenuItemWithCaptionLike(FFileMenu, 'Reopen');
    if Assigned(PreviousMenuItem) then begin
      Index := PreviousMenuItem.MenuIndex;
      if Index>=0 then begin
        FMakeEditable := TMenuItem.Create(FFileMenu);
        FMakeEditable.Caption := 'Ma&ke Editable';
        FMakeEditable.OnClick := MakeEditableClick;
        FFileMenu.Insert(Index, FMakeEditable);
      end;
    end;
  end;
end;

destructor TMakeEditable.Destroy;
begin
  FMakeEditable.Free;
  inherited;
end;

function TMakeEditable.MenuItemWithCaptionLike(const Menu: TMenuItem; const DesiredCaption: string): TMenuItem;
var
  i: Integer;
  Target, Found: string;
begin
  Target := StringReplace(LowerCase(Trim(DesiredCaption)), '&', '', [rfReplaceAll, rfIgnoreCase]);
  for i := 0 to Menu.Count-1 do begin
    Result := Menu.Items[i];
    Found := StringReplace(LowerCase(Trim(Result.Caption)), '&', '', [rfReplaceAll, rfIgnoreCase]);
    if Pos(Target, Found)>0 then begin
      exit;
    end;
  end;
  Result := nil;
end;

procedure TMakeEditable.MakeEditableClick(Sender: TObject);

  procedure MakeFileEditable(const FileName: string);
  var
    Attributes: DWORD;
  begin
    Attributes := GetFileAttributes(PChar(FileName));
    SetFileAttributes(PChar(FileName), Attributes and not FILE_ATTRIBUTE_READONLY);
  end;

var
  FileName: string;
  FileExt: string;
  LinkedFileName: string;
  EditBuffer: IOTAEditBuffer;

begin
  EditBuffer := FEditorServices.TopBuffer;
  FileName := EditBuffer.FileName;
  if FileExists(FileName) then begin
    MakeFileEditable(FileName);
    EditBuffer.IsReadOnly := False;

    FileExt := ExtractFileExt(FileName);
    if SameText(FileExt,'.dfm') then begin
      LinkedFileName := ChangeFileExt(FileName, '.pas');
    end else if SameText(FileExt,'.pas') then begin
      LinkedFileName := ChangeFileExt(FileName, '.dfm');
    end else begin
      LinkedFileName := '';
    end;
    if (LinkedFileName<>'') and FileExists(LinkedFileName) then begin
      MakeFileEditable(LinkedFileName);
    end;
  end;
end;

var
  MakeEditableInstance: TMakeEditable;

procedure Register;
begin
  MakeEditableInstance := TMakeEditable.Create;
end;

initialization

finalization
  MakeEditableInstance.Free;

end.

When you compile and install this package you will now have a new menu item on the File menu which both clears the read-only flag in the input buffer and makes the file writeable.

enter image description here

like image 129
David Heffernan Avatar answered Oct 24 '22 05:10

David Heffernan


You can call a .bat file from the tools menu. So you could write a .bat file to do the work for you, and call it with $EDNAME as the parameter. Your .bat file should see the filename as %1. Then you'd need a little bit of logic to change the read-only flag (attrib command?) and then see if there is a .dfm and do that one as well.

You could also (obviously) make a Delphi command-line app to do this, if you're not comfortable with .bat files.

This idea inspired by this article that talks about how to use a .bat file to integrate SVN commands with the Delphi tools menu: http://delphi.wikia.com/wiki/Adding_TortoiseSVN_to_the_Tools_menu

like image 3
Chris Thornton Avatar answered Oct 24 '22 04:10

Chris Thornton