Code Search for Developers
 
 
  

frmToDo.pas from pyscripter at Krugle


Show frmToDo.pas syntax highlighted

{-----------------------------------------------------------------------------
 Unit Name: frmToDo
 Author:    Kiriakos Vlahos
 Date:      19-May-2005
 Purpose:   Todo list Dock Form based on GExperts unit and covered by its license

GExperts License Agreement
GExperts is copyright 1996-2005 by GExperts, Inc, Erik Berry, and several other
authors who have submitted their code for inclusion. This license agreement only covers code written by GExperts, Inc and Erik Berry. You should contact the other authors concerning their respective copyrights and conditions.

The rules governing the use of GExperts and the GExperts source code are derived
from the official Open Source Definition, available at http://www.opensource.org.
The conditions and limitations are as follows:

    * Usage of GExperts binary distributions is permitted for all developers.
      You may not use the GExperts source code to develop proprietary or
      commercial products including plugins or libraries for those products.
      You may use the GExperts source code in an Open Source project, under the
      terms listed below.
    * You may not use the GExperts source code to create and distribute custom
      versions of GExperts under the "GExperts" name. If you do modify and
      distribute custom versions of GExperts, the binary distribution must be
      named differently and clearly marked so users can tell they are not using
      the official GExperts distribution. A visible and unmodified version of
      this license must appear in any modified distribution of GExperts.
    * Custom distributions of GExperts must include all of the custom changes
      as a patch file that can be applied to the original source code. This
      restriction is in place to protect the integrity of the original author's
      source code. No support for modified versions of GExperts will be provided
      by the original authors or on the GExperts mailing lists.
    * All works derived from GExperts must be distributed under a license
      compatible with this license and the official Open Source Definition,
      which can be obtained from http://www.opensource.org/.
    * Please note that GExperts, Inc. and the other contributing authors hereby
      state that this package is provided "as is" and without any express or
      implied warranties, including, but not without limitation, the implied
      warranties of merchantability and fitness for a particular purpose. In
      other words, we accept no liability for any damage that may result from
      using GExperts or programs that use the GExperts source code.

-----------------------------------------------------------------------------}
// TODO: consider showing the owner and the category

unit frmToDo;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, frmIDEDockWin, JvComponent, JvDockControlForm, ExtCtrls, ActnList,
  Contnrs, ImgList, ComCtrls, Menus, JvAppStorage, JvSearchFiles, TB2Item,
  TBX, TBXThemes, TB2Dock, TB2Toolbar, VirtualTrees, JvComponentBase;

type
  TToDoPriority = (tpHigh, tpMed, tpLow, tpDone);
  TToDoScanType = (tstOpenFiles, tstDirectory);

  TTokenInfo = class(TObject)
  private
    FToken: string;
    FPriority: TToDoPriority;
  public                                       
    property Token: string read FToken write FToken;
    property Priority: TToDoPriority read FPriority write FPriority;
  end;

  TToDoInfo = class(TObject)
  private
    NumericPriority: Cardinal;
    Owner: WideString;
    ToDoClass: WideString;
    //
    Priority: TToDoPriority;
    Raw: WideString;
    Display: WideString;
    FileName: string;
    LineNo: Integer;
  end;

  TTokenList = class(TStringList)
  private
    procedure AddToken(const Token: string; Priority: TToDoPriority);
  public
    destructor Destroy; override;
  end;

  TToDoWindow = class(TIDEDockWindow)
    ilTodo: TImageList;
    Actions: TActionList;
    actFileRefresh: TAction;
    actEditGoto: TAction;
    actFilePrint: TAction;
    actOptionsConfigure: TAction;
    actHelpHelp: TAction;
    actEditCopy: TAction;
    JvSearchFiles: TJvSearchFiles;
    actViewStayOnTop: TAction;
    TBXDock1: TTBXDock;
    Toolbar: TTBXToolbar;
    TBXItem1: TTBXItem;
    TBXItem2: TTBXItem;
    TBXSeparatorItem1: TTBXSeparatorItem;
    TBXSeparatorItem2: TTBXSeparatorItem;
    TBXItem3: TTBXItem;
    TBXSeparatorItem3: TTBXSeparatorItem;
    TBXItem4: TTBXItem;
    TBXSeparatorItem4: TTBXSeparatorItem;
    TBXItem5: TTBXItem;
    PopupMenu: TTBXPopupMenu;
    Goto1: TTBXItem;
    Refresh1: TTBXItem;
    N1: TTBXSeparatorItem;
    CopyAll1: TTBXItem;
    N2: TTBXSeparatorItem;
    Print1: TTBXItem;
    Options1: TTBXItem;
    ToDoView: TVirtualStringTree;
    TBXSeparatorItem5: TTBXSeparatorItem;
    TBXItem6: TTBXItem;
    TBXSeparatorItem6: TTBXSeparatorItem;
    TBXItem7: TTBXItem;
    procedure actEditCopyExecute(Sender: TObject);
    procedure actFilePrintExecute(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure actFilePrintUpdate(Sender: TObject);
    procedure actFileRefreshExecute(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure actEditGotoExecute(Sender: TObject);
    procedure actOptionsConfigureExecute(Sender: TObject);
    procedure actViewStayOnTopExecute(Sender: TObject);
    procedure actViewStayOnTopUpdate(Sender: TObject);
    procedure TodoViewKeyPress(Sender: TObject; var Key: Char);
    procedure ToDoViewInitNode(Sender: TBaseVirtualTree; ParentNode,
      Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
    procedure ToDoViewGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
      Column: TColumnIndex; TextType: TVSTTextType;
      var CellText: WideString);
    procedure ToDoViewGetImageIndex(Sender: TBaseVirtualTree;
      Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
      var Ghosted: Boolean; var ImageIndex: Integer);
    procedure ToDoViewChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
    procedure ToDoViewCompareNodes(Sender: TBaseVirtualTree; Node1,
      Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
    procedure ToDoViewHeaderClick(Sender: TVTHeader; Column: TColumnIndex;
      Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure actHelpHelpExecute(Sender: TObject);
  private
    { Private declarations }
    FIsFirstActivation: Boolean;
    FDataList: TObjectList;
    FScannedFiles: TStringList;
    function GetSelectedItem: TToDoInfo;
    procedure ClearDataListAndListView;
    procedure EnumerateFilesByDirectory;
    procedure EnumerateOpenFiles;
    procedure LoadFile(const FileName: string);
    function ParseComment(const FileName: string; const SComment, EComment,
     TokenString: WideString; LineNumber: Integer): TToDoInfo;
  protected
    procedure TBMThemeChange(var Message: TMessage); message TBM_THEMECHANGE;
  public
    { Public declarations }
    procedure RefreshTodoList;
  end;

  TToDoExpert = class(TInterfacedPersistent, IJvAppStorageHandler)
  private
    FScanType: TToDoScanType;
    FDirsToScan: string;
    FRecurseDirScan: Boolean;
    FTokenList: TTokenList;
    FShowTokens: Boolean;
  protected
    // IJvAppStorageHandler implementation
    procedure ReadFromAppStorage(AppStorage: TJvCustomAppStorage; const BasePath: string);
    procedure WriteToAppStorage(AppStorage: TJvCustomAppStorage; const BasePath: string);
  public
    constructor Create;
    destructor Destroy; override;
    procedure Configure;
  end;

var
  ToDoWindow: TToDoWindow;
  ToDoExpert: TToDoExpert;

implementation

uses dmCommands, Clipbrd, uEditAppIntfs, Math, frmPyIDEMain, dlgToDoOptions,
  uCommonFunctions, JvJVCLUtils, JvDockGlobals, SynUnicode;

{$R *.dfm}

Type

  PToDoRec = ^TToDoRec;
  TToDoRec = record
    ToDoInfo : TToDoInfo;
  end;

function WideCaseInsensitivePos(const SubString, S: WideString): Integer;
begin
  Result := Pos(WideUpperCase(SubString), WideUpperCase(S));
end;

procedure TToDoWindow.actEditCopyExecute(Sender: TObject);
var
  ClipText: TWideStrings;
  i: Integer;
begin
  inherited;

  ClipText := TWideStringList.Create;
  try
    for i := 0 to fDataList.Count - 1 do
    with TToDoInfo(fDataList[i]) do begin
      ClipText.Add(IntToStr(Ord(Priority)) + #9 +
        Display + #9 +
        ExtractFileName(FileName) + #9 +
        IntToStr(LineNo));
    end;
    SetClipboardText(ClipText.Text);
  finally
    FreeAndNil(ClipText);
  end;
end;

procedure TToDoWindow.actOptionsConfigureExecute(Sender: TObject);
begin
  ToDoExpert.Configure;
end;

function TToDoWindow.GetSelectedItem: TToDoInfo;
Var
  Node : PVirtualNode;
begin
  Result := nil;
  Node := ToDoView.GetFirstSelected();
  if Assigned(Node) then
    Result := PToDoRec(ToDoView.GetNodeData(Node))^.ToDoInfo;
end;

procedure TToDoWindow.actFileRefreshExecute(Sender: TObject);
begin
  RefreshTodoList;
end;

procedure TToDoWindow.actEditGotoExecute(Sender: TObject);
Var
  SelectedItem: TToDoInfo;
begin
  SelectedItem := GetSelectedItem;
  if SelectedItem = nil then Exit;

  PyIDEMainForm.ShowFilePosition(SelectedItem.FileName, SelectedItem.LineNo+1, 1);
end;

resourcestring
  SHigh = 'High';
  SNormal = 'Normal';
  SLow = 'Low';
  SDone = 'Done';

var
  PriorityText: array[Low(TToDoPriority)..High(TToDoPriority)] of string =
    (SHigh, SNormal, SLow, SDone);

procedure TToDoWindow.actFilePrintExecute(Sender: TObject);
resourcestring
  STodoItems = 'To Do Items';
var
  RichEdit: TRichEdit;
  i: Integer;
begin
  if fDataList.Count = 0 then
    Exit;

  RichEdit := TRichEdit.Create(Self);
  try
    RichEdit.Visible := False;
    RichEdit.Parent := Self;
    RichEdit.Clear;
    RichEdit.Lines.Add('');
    with RichEdit.SelAttributes do
    begin
      Style := [fsBold];
      Size := 14;
    end;

    with RichEdit.SelAttributes do begin
      Style := [fsBold];
      RichEdit.Lines.Add(STodoItems);
      Style := [];
    end;
    for i := 0 to FDataList.Count - 1 do
    begin
      with TToDoInfo(FDataList[i]) do
      begin
        with RichEdit.SelAttributes do
        begin
          case Priority of
            tpHigh   : Style := [fsBold];
            tpMed : Style := [];
            tpLow    : Style := [fsItalic];
          end;
          Size := 10;
        end;
        RichEdit.Lines.Add(ExtractFileName(FileName) + ' (' + IntToStr(LineNo) + ')' +
          #09 + PriorityText[Priority] + #9 + Display);
      end;
    end;
    RichEdit.Print(SToDoItems);
  finally
    FreeAndNil(RichEdit);
  end;
end;

procedure TToDoWindow.actFilePrintUpdate(Sender: TObject);
begin
  (Sender as TAction).Enabled := (FDataList.Count > 0);
end;

procedure TToDoWindow.FormCreate(Sender: TObject);
begin
  inherited;
  FIsFirstActivation := True;

  FDataList := TObjectList.Create(True); // Owned objects
  FScannedFiles := TStringList.Create;

  // Let the tree know how much data space we need.
  ToDoView.NodeDataSize := SizeOf(TToDoRec);
  ToDoView.OnAdvancedHeaderDraw :=
    CommandsDataModule.VirtualStringTreeAdvancedHeaderDraw;
  ToDoView.OnHeaderDrawQueryElements :=
    CommandsDataModule.VirtualStringTreeDrawQueryElements;
end;

procedure TToDoWindow.FormDestroy(Sender: TObject);
begin
  ClearDataListAndListView;

  FreeAndNil(FDataList);
  FreeAndNil(FScannedFiles);

  inherited;
end;

procedure TToDoWindow.ClearDataListAndListView;
begin
  ToDoView.Clear;
  FDataList.Clear;
end;

{ TTokenList }

procedure TTokenList.AddToken(const Token: string;
  Priority: TToDoPriority);
Var
  TokenInfo: TTokenInfo;
begin
  TokenInfo := TTokenInfo.Create;
  TokenInfo.Token := Token;
  TokenInfo.Priority := Priority;

  AddObject(Token, TokenInfo);
end;

destructor TTokenList.Destroy;
var
  i: Integer;
begin
  for i := Count - 1 downto 0 do
    Objects[i].Free;
  inherited;
end;

{ TToDoExpert }

procedure TToDoExpert.Configure;
var
  Dlg: TfmToDoOptions;
  TodoListOptionsUnchanged: Boolean;
  OldScanType: TToDoScanType;
begin
  TodoListOptionsUnchanged := True;

  Dlg := TfmToDoOptions.Create(nil);
  try
    Dlg.lstTokens.Items.Assign(FTokenList);
    Dlg.cbShowTokens.Checked := FShowTokens;
    case FScanType of
      tstOpenFiles:
        Dlg.radScanOpen.Checked := True;
      tstDirectory:
        Dlg.radScanDir.Checked := True;
    end;
    Dlg.chkInclude.Checked := FRecurseDirScan;
    Dlg.meDirectories.Text := FDirsToScan;

    if Dlg.ShowModal = mrOk then
    begin
      TodoListOptionsUnchanged := TodoListOptionsUnchanged and
        FTokenList.Equals(Dlg.lstTokens.Items);
      FTokenList.Assign(Dlg.lstTokens.Items);

      TodoListOptionsUnchanged := TodoListOptionsUnchanged and
        (FShowTokens = Dlg.cbShowTokens.Checked);
      FShowTokens := Dlg.cbShowTokens.Checked;

      OldScanType := FScanType;

      if Dlg.radScanOpen.Checked then
        FScanType := tstOpenFiles
      else if Dlg.radScanDir.Checked then
        FScanType := tstDirectory;

      TodoListOptionsUnchanged := TodoListOptionsUnchanged and
        (FScanType = OldScanType);

      TodoListOptionsUnchanged := TodoListOptionsUnchanged and
        (FRecurseDirScan = Dlg.chkInclude.Checked);
      FRecurseDirScan := Dlg.chkInclude.Checked;

      TodoListOptionsUnchanged := TodoListOptionsUnchanged and
        (AnsiCompareText(FDirsToScan, Dlg.meDirectories.Text) = 0);
      FDirsToScan := Dlg.meDirectories.Text;
    end;
  finally
    FreeAndNil(Dlg);
  end;

  if not TodoListOptionsUnchanged then
  begin
    if Assigned(ToDoWindow) then
      ToDoWindow.RefreshTodoList;
  end;
end;

constructor TToDoExpert.Create;
begin
  inherited;
  FTokenList := TTokenList.Create;
  FScanType := tstOpenFiles;
  // Initialize FTokenList
  with FTokenList do begin
    AddToken('TODO', tpMed);
    AddToken('FIXME', tpMed);
    AddToken('XXX', tpMed);
    AddToken('ToDo1', tpHigh);
    AddToken('ToDo2', tpMed);
    AddToken('ToDo3', tpLow);
  end;
end;

destructor TToDoExpert.Destroy;
begin
  FreeAndNil(FTokenList);

  ToDoExpert := nil;
  inherited;
end;

procedure TToDoExpert.ReadFromAppStorage(AppStorage: TJvCustomAppStorage;
  const BasePath: string);
Var
  i : integer;
  NTokens : integer;
  Priority : TToDoPriority;
  Token : string;
  SL : TStringList;
begin
  with AppStorage do begin
    FShowTokens := ReadBoolean(BasePath+'\ShowTokens');
    ReadEnumeration(BasePath+'\ScanType', TypeInfo(TToDoScanType), FScanType, FScanType);
    SL := TStringList.Create;
    try
      ReadStringList(BasePath+'\DirsToScan', SL);
      FDirsToScan := SL.Text;
    finally
      SL.Free;
    end;
    FRecurseDirScan := ReadBoolean(BasePath+'\RecurseDirScan');
    NTokens := ReadInteger(AppStorage.ConcatPaths([BasePath, 'Todo Tokens', 'Count']));
    if NTokens > 0 then begin
      FTokenList.Free;
      FTokenList := TTokenList.Create;
      for i := 0 to NTokens - 1 do begin
        Token := ReadString(AppStorage.ConcatPaths([BasePath, 'Todo Tokens', 'Token'+IntToStr(i), 'Token']));
        Priority := tpMed;
        ReadEnumeration(AppStorage.ConcatPaths([BasePath, 'Todo Tokens', 'Token'+IntToStr(i), 'Priority']),
          TypeInfo(TToDoPriority), Priority, Priority);
        FTokenList.AddToken(Token, Priority);
      end;
    end;
  end;
end;

procedure TToDoExpert.WriteToAppStorage(AppStorage: TJvCustomAppStorage;
  const BasePath: string);
Var
  i : integer;
  SL : TStringList;
begin
  with AppStorage do begin
    WriteBoolean(BasePath+'\ShowTokens', FShowTokens);
    WriteEnumeration(BasePath+'\ScanType', TypeInfo(TToDoScanType), FScanType);
    SL := TStringList.Create;
    try
      SL.Text := FDirsToScan;
      WriteStringList(BasePath+'\DirsToScan', SL);
    finally
      SL.Free;
    end;
    WriteBoolean(BasePath+'\RecurseDirScan', FRecurseDirScan);
    DeleteSubTree(ConcatPaths([BasePath, 'Todo Tokens']));
    WriteInteger(AppStorage.ConcatPaths([BasePath, 'Todo Tokens', 'Count']), FTokenList.Count);
    for i := 0 to FTokenList.Count - 1 do begin
      WriteString(AppStorage.ConcatPaths([BasePath, 'Todo Tokens', 'Token'+IntToStr(i), 'Token']),
        FTokenList[i]);
      WriteEnumeration(AppStorage.ConcatPaths([BasePath, 'Todo Tokens', 'Token'+IntToStr(i), 'Priority']),
        TypeInfo(TToDoPriority), TTokenInfo(FTokenList.Objects[i]).Priority);
    end;
  end;
end;

resourcestring
  SDoneTodoDesignation = 'Done';

function TToDoWindow.ParseComment(const FileName: string; const SComment, EComment,
  TokenString: WideString; LineNumber: Integer) : TToDoInfo;
var
  i, j, k, n, m, TokenPos, NextCharPos: Integer;
  IsDoneTodoItem: Boolean;
  ParsingString: WideString;
  OptionChar: WideChar;
begin
  Result := nil;
  for i := 0 to ToDoExpert.FTokenList.Count - 1 do
  begin
    n := WideCaseInsensitivePos(ToDoExpert.FTokenList[i], TokenString);
    if n > 1 then
    begin
      // We found a token that looks like a TODO comment. Now
      // verify that it *is* one: either a white-space or the
      // comment token need to be right in front of the TODO item

      // Remove comment characters
      ParsingString := TokenString;
      Delete(ParsingString, 1, Length(SComment));
      // Remove white-space left and right
      ParsingString := Trim(ParsingString);

      // The TODO token should be at the beginning of the comment
      TokenPos := WideCaseInsensitivePos(ToDoExpert.FTokenList[i], ParsingString);
      if TokenPos <> 1 then
        Continue;

      // The TODO token should be followed by a non-alphanumeric character
      NextCharPos := TokenPos + Length(ToDoExpert.FTokenList[i]);
      if (NextCharPos <= Length(ParsingString)) and IsCharAlphaNumericW(ParsingString[NextCharPos]) then
        Continue;

      // Token found in comment line
      Result := TToDoInfo.Create;

      // Remove token from string
      Delete(ParsingString, 1, Length(ToDoExpert.FTokenList[i]));
      ParsingString := TrimRight(ParsingString);

      // Identify numeric priority (if there is one)
      j := 0;
      while j < Length(ParsingString) do
      begin
        if not (ParsingString[j + 1] in [WideChar('0')..WideChar('9')]) then
          Break;
        Inc(j);
      end;
      Result.NumericPriority := StrToIntDef(Copy(ParsingString, 1, j), 0);
      Delete(ParsingString, 1, j);
      ParsingString := TrimLeft(ParsingString);

      IsDoneTodoItem := (WideCaseInsensitivePos(SDoneTodoDesignation, ParsingString) = 1);

      { zTODO -oTestCase: -cIssue <-- test case for colon }
      // Delete everything being with a possible trailing colon:
      j := Pos(WideChar(':'), ParsingString);
      if j > 0 then
        Delete(ParsingString, j, Length(ParsingString))
      else
        ParsingString := '';

      { zTODO -cSomething -oTestCase: <-- test case for -o switch }
      { zTODO blah -cSomething -oTestCase: <-- this is a deliberately broken item }
      { zTODO -oTestCase -cTest -c switch: <-- test case for -c switch }
      { zTODO -oTestCase -cTest -c switch: <-- another test case for -c switch }
      { zTODO -oTestCase -cTest -zWhoops -c switch: <-- -z switch }
      { zTODO -oTestCase -cTest -z-z-z-z -------------- -c switch: <-- try to break it }
      { zTODO -oTestCase -cTe-st : <-- hyphen test }
      //zTOdo
      { zTODO -oTestCase
          -cMultiline
          <-- Multiline test }
      // Identify owner of TODO item (-o)
      // Identify class of TODO item (-c)
      OptionChar := WideChar(#0); // Initialize to make compiler happy - redundant
      while Pos(WideChar('-'), ParsingString) > 0 do
      begin
        if Length(ParsingString) > 1 then
        begin
          OptionChar := WideUpperCase(Copy(ParsingString, 2, 1))[1];
          Delete(ParsingString, 1, 2);
        end
        else
          Break;

        // Find char immediately preceding the next option switch
        j := Pos('-', ParsingString) - 1;
        if j > 0 then
          k := j
        else
          k := Length(ParsingString);

        case OptionChar of
          'O': Result.Owner := Trim(Copy(ParsingString, 1, k));
          'C': Result.ToDoClass := Trim(Copy(ParsingString, 1, k));
        end;

        // Delete everything up to, but not including, the
        // next option switch
        Delete(ParsingString, 1, j);
      end;

      Result.Raw := TokenString;

      if IsDoneTodoItem then
        Result.Priority := tpDone
      else
        Result.Priority := TTokenInfo(ToDoExpert.FTokenList.Objects[i]).Priority;

      if not ToDoExpert.FShowTokens then begin
        n := n + Length(ToDoExpert.FTokenList[i]);
        // Do not show anything up to ':'
        n := Max(n, Pos(':', TokenString)+1);
      end;
      if EComment <> '' then // Trim end-comment token.
        m := WideCaseInsensitivePos(EComment, TokenString) - 1
      else
        m := Length(TokenString);
      if m < 1 then
        m := Length(TokenString);
      // Prevent multi-line to do notes
      j := Pos(WideChar(#13), TokenString);
      k := Pos(WideChar(#10), TokenString);
      if j = 0 then j := 999999;
      if k = 0 then k := 999999;
      m := Min(m, Min(j, k));
      // The +1 is necessary to match IDE's line numbering
      Result.Display := Trim(Copy(TokenString, n, (m - n) + 1));
      Result.LineNo := LineNumber;
      Result.FileName := FileName;
      FDataList.Add(Result);

      Break; // Comment line parsed, stop searching for more To Do items in that line
    end;
  end;
end;

procedure TToDoWindow.LoadFile(const FileName: string);
Var
  SourceCode : TWideStringList;
  Editor : IEditor;
  i, Index : integer;
  TokenString : WideString;
  Encoding : TFileSaveFormat;
  Info, Info2 : TToDoInfo;
begin
  SourceCode := TWideStringList.Create;
  try
    //  Read file into SourceCode
    Editor := GI_EditorFactory.GetEditorByNameOrTitle(FileName);
    if Assigned(Editor) then
      SourceCode.Assign(Editor.SynEdit.Lines)
    else begin
      if not LoadFileIntoWideStrings(FileName, SourceCode, Encoding) then Exit;
    end;

    // scan source code
    i := 0;
    Info := nil;
    while i < SourceCode.Count do begin
      TokenString := TrimLeft(SourceCode[i]);
      if (Info <> nil) and (Length(TokenString) > 1) and (TokenString[1] = WideChar('#')) then begin
        // Check for multiline comments
        Info2 := ParseComment(FileName, '#', '', TokenString, i);
        if Info2 = nil then
          // Append new comment to Info.Display
          Info.Display := Info.Display + ' ' +
            Copy(TokenString, 2, Length(TokenString)-1)
        else
          Info := Info2;
      end else begin
        Info := nil;
        Index := Pos(WideChar('#'), TokenString);
        if Index > 0 then begin
          TokenString := Copy(TokenString, Index, Length(TokenString) - Index + 1);
          Info := ParseComment(FileName, '#', '', Tokenstring, i);
        end;
      end;
      Inc(i);
    end;
  finally
    SourceCode.Free;
  end;
end;

procedure TToDoWindow.RefreshTodoList;
var
  Cursor: IInterface;
begin
  Application.ProcessMessages;  // to repaint etc.
  Cursor := WaitCursor;
  try
    FScannedFiles.Clear;
    ClearDataListAndListView;

    case ToDoExpert.FScanType of
      tstOpenFiles:
        EnumerateOpenFiles;
      tstDirectory:
        begin
          if Trim(ToDoExpert.FDirsToScan) <> '' then
            EnumerateFilesByDirectory;
        end;
    end;
    ToDoView.RootNodeCount := FDataList.Count;

  finally
    if FDataList.Count > 0 then
    begin
      if Assigned(ToDoView.RootNode.FirstChild) then
        ToDoView.Selected[ToDoView.RootNode.FirstChild] := True;
      actEditGoto.Enabled := True;
    end
    else
      actEditGoto.Enabled := False;
  end;
end;

procedure TToDoWindow.EnumerateFilesByDirectory;
Var
  Dirs: TStringList;
  i, j : integer;
begin
  JvSearchFiles.FileParams.FileMaskSeperator := ';';
  JvSearchFiles.FileParams.FileMask := CommandsDataModule.PyIDEOptions.FileExplorerFilter;
  JvSearchFiles.FileParams.SearchTypes := [stFileMask];

  Dirs := TStringList.Create;
  Dirs.Text := ToDoExpert.FDirsToScan;
  try
    for i := 0 to Dirs.Count - 1 do begin
      jvSearchFiles.RootDirectory := Dirs[i];
      if ToDoExpert.FRecurseDirScan then
        JvSearchFiles.DirOption := doIncludeSubDirs
      else
        JvSearchFiles.DirOption := doExcludeSubDirs;
      if JvSearchFiles.Search then begin
        for j := 0 to JvSearchFiles.Files.Count - 1 do
          LoadFile(JvSearchFiles.Files[j]);
      end;
    end;
  finally
    Dirs.Free;
  end;
end;

procedure TToDoWindow.EnumerateOpenFiles;
var
  i : integer;
  FileName : string;
  Editor : IEditor;
begin
  for i := 0 to GI_EditorFactory.Count - 1 do begin
    Editor := GI_EditorFactory.Editor[i];
    FileName := Editor.GetFileNameOrTitle;
    LoadFile(FileName);
  end;
end;

procedure TToDoWindow.FormActivate(Sender: TObject);
begin
  inherited;
  if FIsFirstActivation then
  begin
    FIsFirstActivation := False;
    RefreshTodoList;
  end;
  if not HasFocus then begin
    FGPanelEnter(Self);
    PostMessage(ToDoView.Handle, WM_SETFOCUS, 0, 0);
  end;
end;

procedure TToDoWindow.actViewStayOnTopExecute(Sender: TObject);
begin
  if FormStyle = fsNormal then
    FormStyle := fsStayOnTop
  else
    FormStyle := fsNormal;
end;

procedure TToDoWindow.actViewStayOnTopUpdate(Sender: TObject);
begin
  actViewStayOnTop.Checked := FormStyle = fsStayOnTop;
end;

procedure TToDoWindow.TodoViewKeyPress(Sender: TObject; var Key: Char);
begin
  if key = #13 then begin
    actEditGotoExecute(Self);
    Key := #0;
  end;
end;

procedure TToDoWindow.TBMThemeChange(var Message: TMessage);
begin
  inherited;
  if Message.WParam = TSC_VIEWCHANGE then begin
    ToDoView.Header.Invalidate(nil, True);
    ToDoView.Colors.HeaderHotColor :=
      CurrentTheme.GetItemTextColor(GetItemInfo('active'));
  end;
end;

procedure TToDoWindow.ToDoViewInitNode(Sender: TBaseVirtualTree;
  ParentNode, Node: PVirtualNode;
  var InitialStates: TVirtualNodeInitStates);
begin
  Assert(ToDoView.GetNodeLevel(Node) = 0);
  Assert(Integer(Node.Index) < fDataList.Count);
  PToDoRec(ToDoView.GetNodeData(Node))^.ToDoInfo :=
    fDataList[Node.Index] as TToDoInfo;
end;

procedure TToDoWindow.ToDoViewGetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: WideString);
begin
  Assert(ToDoView.GetNodeLevel(Node) = 0);
  Assert(Integer(Node.Index) < fDataList.Count);
  with PToDoRec(ToDoView.GetNodeData(Node))^.ToDoInfo do
    case Column of
      1:  CellText := Display;
      2:  CellText := ExtractFileName(FileName);
      3:  CellText := IntToStr(LineNo);
    end;
end;

procedure TToDoWindow.ToDoViewGetImageIndex(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
  var Ghosted: Boolean; var ImageIndex: Integer);
begin
  if (Kind in [ikNormal, ikSelected]) and (Column = 0) then begin
    Assert(ToDoView.GetNodeLevel(Node) = 0);
    Assert(Integer(Node.Index) < fDataList.Count);
    with PToDoRec(ToDoView.GetNodeData(Node))^.ToDoInfo do
      ImageIndex := Ord(Priority);
  end;
end;

procedure TToDoWindow.ToDoViewChange(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
begin
  actEditGoto.Enabled := Assigned(Node);
end;

procedure TToDoWindow.ToDoViewCompareNodes(Sender: TBaseVirtualTree; Node1,
  Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
Var
  ToDoInfo1, ToDoInfo2 : TTodoInfo;
begin
  Assert(Assigned(Node1) and Assigned(Node2));
  ToDoInfo1 := PToDoRec(TodoView.GetNodeData(Node1))^.ToDoInfo;
  ToDoInfo2 := PToDoRec(TodoView.GetNodeData(Node2))^.ToDoInfo;
  case Column of
    -1: Result := 0;
    0: Result := Ord(ToDoInfo1.Priority) - Ord(ToDoInfo2.Priority);
    1: Result := WideCompareStr(ToDoInfo1.Display, ToDoInfo2.Display);
    2: Result := AnsiCompareStr(ExtractFileName(ToDoInfo1.FileName),
                    ExtractFileName(ToDoInfo2.FileName));
    3: Result := ToDoInfo1.LineNo - ToDoInfo2.LineNo;
  end;
end;

procedure TToDoWindow.ToDoViewHeaderClick(Sender: TVTHeader;
  Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
begin
  if ToDoView.Header.SortColumn = Column then begin
    if ToDoView.Header.SortDirection = sdAscending then
      ToDoView.Header.SortDirection := sdDescending
    else
      ToDoView.Header.SortDirection := sdAscending;
  end else
    ToDoView.Header.SortColumn := Column;
  if ToDoView.Header.SortColumn = 0 then
    ToDoView.Header.Columns[0].Alignment := taLeftJustify  // to make it fit
  else
    ToDoView.Header.Columns[0].Alignment := taCenter;
end;

procedure TToDoWindow.actHelpHelpExecute(Sender: TObject);
begin
  Application.HelpContext(HelpContext);
end;

initialization
  ToDoExpert := TToDoExpert.Create;
finalization
  ToDoExpert.Free;
end.








See more files for this project here

pyscripter

PyScripter is a free and open-source Python Integrated Development Environment (IDE) created with the ambition to become competitive in functionality with commercial Windows-based IDEs available for other languages. Being built in a compiled language is rather snappier than some of the other Python IDEs and provides an extensive blend of features that make it a productive Python development environment.

Project homepage: http://code.google.com/p/pyscripter/
Programming language(s): Pascal
License: mit

  Components/
  FastMM4Options.inc
  Install.txt
  JvAppIniStorage.pas
  JvAppInst.pas
  JvAppStorage.pas
  JvChangeNotify.pas
  JvCreateProcess.pas
  JvDockControlForm.pas
  JvDockInfo.pas
  JvDockVSNetStyle.pas
  JvProgramVersionCheck.pas
  JvTabBar.pas
  JvThread.pas
  PyScripter Logo.bmp
  PyScripter.bdsproj
  PyScripter.bdsproj.local
  PyScripter.dpr
  PyScripter.ico
  PyScripter.res
  Readme.txt
  StoHtmlHelp.pas
  StringResources.pas
  SynCompletionProposal.pas
  SynEdit.pas
  SynEditKeyCmds.pas
  SynHighlighterPython.pas
  cCodeHint.pas
  cFilePersist.pas
  cFileSearch.pas
  cFileTemplates.pas
  cFindInFiles.pas
  cParameters.pas
  cPyBaseDebugger.pas
  cPyDebugger.pas
  cPyRemoteDebugger.pas
  cPythonSourceScanner.pas
  cRefactoring.pas
  cTools.pas
  dlgAboutPyScripter.dfm
  dlgAboutPyScripter.pas
  dlgAskParam.dfm
  dlgAskParam.pas
  dlgCodeTemplates.dfm
  dlgCodeTemplates.pas
  dlgCommandLine.dfm
  dlgCommandLine.pas
  dlgConfigureTools.dfm
  dlgConfigureTools.pas
  dlgConfirmReplace.dfm
  dlgConfirmReplace.pas
  dlgCustomParams.dfm
  dlgCustomParams.pas
  dlgCustomShortcuts.dfm
  dlgCustomShortcuts.pas
  dlgDirectoryList.dfm
  dlgDirectoryList.pas
  dlgExceptionMail.dfm
  dlgExceptionMail.pas
  dlgFileTemplates.dfm
  dlgFileTemplates.pas
  dlgFindInFiles.dfm
  dlgFindInFiles.pas
  dlgFindResultsOptions.dfm
  dlgFindResultsOptions.pas
  dlgNewFile.dfm
  dlgNewFile.pas
  dlgOptionsEditor.dfm
  dlgOptionsEditor.pas
  dlgPickList.dfm
  dlgPickList.pas
  dlgReplaceInFiles.dfm
  dlgReplaceInFiles.pas
  dlgReplaceText.dfm
  dlgReplaceText.pas
  dlgSearchText.dfm
  dlgSearchText.pas
  dlgSynEditOptions.dfm
  dlgSynEditOptions.pas
  dlgSynPageSetup.dfm
  dlgSynPageSetup.pas
  dlgSynPrintPreview.dfm
  dlgSynPrintPreview.pas
  dlgToDoOptions.dfm
  dlgToDoOptions.pas
  dlgToolProperties.dfm
  dlgToolProperties.pas
  dlgUnitTestWizard.dfm
  dlgUnitTestWizard.pas
  dmCommands.dfm
  dmCommands.pas
  frmBreakPoints.dfm
  frmBreakPoints.pas
  frmCallStack.dfm
  frmCallStack.pas
  frmCodeExplorer.dfm
  frmCodeExplorer.pas
  frmCommandOutput.dfm
  frmCommandOutput.pas
  frmDisassemlyView.dfm
  frmDisassemlyView.pas
  frmDocView.dfm
  frmDocView.pas
  frmEditor.dfm
  frmEditor.pas
  frmFileExplorer.dfm
  frmFileExplorer.pas
  frmFindResults.dfm
  frmFindResults.pas
  frmFunctionList.dfm
  frmFunctionList.pas
  frmIDEDockWin.dfm
  frmIDEDockWin.pas
  frmMessages.dfm
  frmMessages.pas
  frmPyIDEMain.dfm
  frmPyIDEMain.pas
  frmPythonII.dfm
  frmPythonII.pas
  frmRegExpTester.dfm
  frmRegExpTester.pas
  frmToDo.dfm
  frmToDo.pas
  frmUnitTests.dfm
  frmUnitTests.pas
  frmVariables.dfm
  frmVariables.pas
  frmWatches.dfm
  frmWatches.pas
  uCommonFunctions.pas
  uEditAppIntfs.pas
  uHighlighterProcs.pas
  uMMMXP_MainService.pas
  uParams.pas