{*****************************************************************************
 *
 *  FMToDoEx
 *
 *      ToDoEx window
 *
 *  Copyright (c) 2002 Arthur Hoogervorst
 *
 *  Author:     Arthur Hoogervorst
 *  E-mail:     ahooger@istar.ca
 *  Homepage:   http://roundabout.sourceforge.net
 *
 *  This program 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;
 *
 *  This program 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.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
 *
 *----------------------------------------------------------------------------
 *
 *  Revision history:
 *
 *     DATE     REV                 DESCRIPTION
 *  ----------- --- ----------------------------------------------------------
 *  2002        1.0    Initial Release of ToDO window
 *****************************************************************************}

unit FMToDOEx;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  GradForm, ImgList, ComCtrls, EnhListView, ExtListView, Menus, ToolWin,
  StdCtrls, pmToDo, ExtCtrls, RichEdit2, ActnList, iniFiles;

type
  TToDoEx = class(TdfsGradientForm)
    ImageList1: TImageList;
    PopupMenu1: TPopupMenu;
    N1: TMenuItem;
    Properties1: TMenuItem;
    ToDoitem2: TMenuItem;
    StatusBar1: TStatusBar;
    ToDoItem1: TMenuItem;
    Splitter1: TSplitter;
    Panel1: TPanel;
    RichEdit1: TRichEdit98;
    ActionList1: TActionList;
    actCategoryNew: TAction;
    actToDoNew: TAction;
    actToDoDelete: TAction;
    actToDoProperties: TAction;
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    New2: TMenuItem;
    DeleteToDo1: TMenuItem;
    N3: TMenuItem;
    Properties2: TMenuItem;
    N2: TMenuItem;
    Close1: TMenuItem;
    View1: TMenuItem;
    Category3: TMenuItem;
    New3: TMenuItem;
    N5: TMenuItem;
    CopyItem1: TMenuItem;
    MoveItem1: TMenuItem;
    Edit1: TMenuItem;
    N6: TMenuItem;
    N7: TMenuItem;
    Export1: TMenuItem;
    Extra1: TMenuItem;
    actClose: TAction;
    actCategoryEditor: TAction;
    Showlines1: TMenuItem;
    Showcolours1: TMenuItem;
    Panel2: TPanel;
    ListView1: TdfsExtListView;
    N4: TMenuItem;
    CopyItem2: TMenuItem;
    MoveItem2: TMenuItem;
    procedure ListView1DrawItem(Control: TWinControl;
      var ACanvas: TCanvas; Index: Integer; ARect: TRect;
      State: TOwnerDrawState; var DefaultDrawing, FullRowSelect: Boolean);
    procedure dfsGradientFormCreate(Sender: TObject);
    procedure ListView1Click(Sender: TObject);
    procedure actCategoryNewExecute(Sender: TObject);
    procedure actToDoNewExecute(Sender: TObject);
    procedure actToDoNewUpdate(Sender: TObject);
    procedure actToDoPropertiesExecute(Sender: TObject);
    procedure actToDoDeleteExecute(Sender: TObject);
    procedure actToDoDeleteUpdate(Sender: TObject);
    procedure actCloseExecute(Sender: TObject);
    procedure actCategoryEditorExecute(Sender: TObject);
    procedure Showlines1Click(Sender: TObject);
    procedure Showcolours1Click(Sender: TObject);
    procedure dfsGradientFormDestroy(Sender: TObject);
    procedure dfsGradientFormShow(Sender: TObject);
    procedure ListView1SortBegin(Sender: TObject; SortColumn: Integer;
      Ascending: Boolean);
  private
    { Private declarations }
  protected
    { Protected declarations }
  public
    { Public declarations }
    procedure UpdateShowLines;
    procedure UpdateList;
    procedure UpdateRichEdit;
    procedure DBRefresh(Category : string);
    procedure MenuRefresh;
    procedure MenuSelectionClick(Sender: TObject);
    procedure CopySelectionClick(Sender: TObject);
    procedure MoveSelectionClick(Sender: TObject);
  published
    { Published declarations }
  end;

var
  ToDoEx : TToDoEx;

implementation

uses FMToDoProp, FMCats, PXStuff, Main, ELVSup;

{$R *.DFM}

procedure TToDoEx.UpdateShowLines;
begin
  if ShowLines1.Checked then
    ListView1.ExtendedStyles := ListView1.ExtendedStyles + [lvxGridLines]
  else
    ListView1.ExtendedStyles := ListView1.ExtendedStyles - [lvxGridLines];
end;

procedure TToDoEx.UpdateRichEdit;
begin
  RichEdit1.Clear;
  if (ListView1.Selected <> nil) and (ListView1.SelCount = 1) then
  begin
    RichEdit1.Lines.BeginUpdate;

    RichEdit1.SelAttributes.Style := [fsBold];
    RichEdit1.Paragraph.Alignment := taCenter;
    RichEdit1.SelAttributes.Size := RichEdit1.Font.Size + 2;
    RichEdit1.SelText := GetMessageString(150) + #13#10+#13#10;

    RichEdit1.Paragraph.Alignment := taLeft;
    RichEdit1.SelAttributes.Size := RichEdit1.Font.Size;
    RichEdit1.SelAttributes.Style := [fsBold];
    RichEdit1.SelText := GetMessageString(151) + ': ';
    RichEdit1.SelAttributes.Style := [];
    RichEdit1.SelText := ListView1.Selected.SubItems[siCategory] + #13#10;
    RichEdit1.Selattributes.Style := [fsBold];
    RichEdit1.SelText := GetMessageString(152) + ': ';
    RichEdit1.SelAttributes.Style := [];
    RichEdit1.SelText := ListView1.Selected.SubItems[siDescription] + #13#10;

    if ListView1.Selected.SubItems[siPriority] <> '' then
    begin
      RichEdit1.Selattributes.Style := [fsBold];
      RichEdit1.SelText := GetMessageString(153) + ': ';
      RichEdit1.SelAttributes.Style := [];
      RichEdit1.Seltext := ListView1.Selected.SubItems[siPriority] + #13#10;
    end;

    if (ListView1.Selected.SubItems[siStartDate] <> '') or
      (ListView1.Selected.SubItems[siEndDate] <> '') or
      (ListView1.Selected.SubItems[siDueDate] <> '') then
    begin
      RichEdit1.SelAttributes.Style := [fsBold];
      RichEdit1.Paragraph.Alignment := taCenter;
      RichEdit1.SelText := '_______'#13#10#13#10;

      RichEdit1.Paragraph.Alignment := taLeft;
      if ListView1.Selected.SubItems[siStartDate] <> '' then
      begin
        RichEdit1.SelAttributes.Style := [fsBold];
        RichEdit1.SelText := GetMessageString(154) + ': ';
        RichEdit1.SelAttributes.Style := [];
        RichEdit1.SelText :=  ListView1.Selected.SubItems[siStartDate] + #13#10;
      end;

      if ListView1.Selected.SubItems[siDueDate] <> '' then
      begin
        RichEdit1.SelAttributes.Style := [fsBold];
        RichEdit1.SelText := GetMessageString(155) + ': ';
        RichEdit1.SelAttributes.Style := [];
        RichEdit1.SelText :=  ListView1.Selected.SubItems[siDueDate] + #13#10;
      end;

      if ListView1.Selected.SubItems[siEndDate] <> '' then
      begin
        RichEdit1.SelAttributes.Style := [fsBold];
        RichEdit1.SelText := GetMessageString(156) + ': ';
        RichEdit1.SelAttributes.Style := [];
        RichEdit1.SelText :=  ListView1.Selected.SubItems[siEndDate] + #13#10;
      end;
    end;

    RichEdit1.SelAttributes.Style := [fsBold];
    RichEdit1.Paragraph.Alignment := taCenter;
    RichEdit1.SelText := '_______'#13#10#13#10;
    RichEdit1.Paragraph.Alignment := taLeft;
    RichEdit1.SelAttributes.Style := [];
    RichEdit1.SelText := ListView1.Selected.SubItems[siNotes] + #13#10;
    RichEdit1.Lines.EndUpdate;
  end
end;

procedure TToDoEx.UpdateList;
var s : string;
   x : integer;
begin
  ListView1.Items.BeginUpdate;
  ListView1.Items.Clear;
  ListView1.Items.EndUpdate;
  for x := 0 to View1.Count -1 do
  begin
    if View1.Items[x].Checked then
    begin
      s := StripHotKey(View1.Items[x].Caption);
      DBRefresh(s)
    end;
  end;
  UpdateRichEdit;
  Statusbar1.Panels[0].Text := Format(GetMessageString(111),
          [IntToStr(ListView1.Items.Count)])
end;

procedure TToDoEx.MenuSelectionClick(Sender: TObject);
begin
  (Sender as TMenuItem).Checked := not (Sender as TMenuItem).Checked;
  UpdateList;
end;

procedure TToDoEx.CopySelectionClick(Sender: TObject);
var t : TToDoFile;
    m : TToDoItem;
    li : TListItem;
    afile, mfile : string;
begin
  if Sender is TMenuItem then
  begin
    if ListView1.Selected <> nil then
    begin
      li := ListView1.Selected;
      while li <> nil do
      begin
        afile := SToDoFolder + (
          StripHotKey((Sender as TMenuItem).Caption) + '.ptd');
        if fileExists(afile) then
        begin
          // Get recordnumber....
          mfile := sToDoFolder +  li.SubItems[siCategory] + '.ptd';
          t := TToDoFile.Create(mfile, fmOpenRead);
          // Open the record and assign to m
          m := t.ToDoItem[StrToInt(li.SubItems[siRecordNumber])];
          t.Free;
          // Add the item again...
          t := TToDoFile.Create(afile, fmOpenReadWrite);
          t.Add(m);
          t.Free;
        end;
        li := ListView1.GetNextItem(li, sdAll, [isSelected]);
      end;
    end;
    UpdateList;    
  end;
end;

procedure TToDoEx.MoveSelectionClick(Sender: TObject);
var t : TToDoFile;
    m : TToDoItem;
    li : TListItem;
    afile, mfile : string;
begin
  if ListView1.Selected <> nil then
  begin
    li := ListView1.Selected;
    while li <> nil do
    begin
      afile := SToDoFolder + (
        StripHotKey((Sender as TMenuItem).Caption) + '.ptd');
      if fileExists(afile) then
      begin
        // Get recordnumber....
        mfile := sToDoFolder +  li.SubItems[siCategory] + '.ptd';
        t := TToDoFile.Create(mfile, fmOpenReadWrite);
        // Open the record and assign to m
        m := t.ToDoItem[StrToInt(li.SubItems[siRecordNumber])];
        t.Delete(StrToInt(li.SubItems[siRecordNumber]));
        t.Free;
        // Add the item again...
        t := TToDoFile.Create(afile, fmOpenReadWrite);
        t.Add(m);
        t.Free;
      end;
      li := ListView1.GetNextItem(li, sdAll, [isSelected]);
    end;
    UpdateList;
  end;
end;

procedure TToDoEX.MenuRefresh;
var l : TStringList;
    x : integer;
    t, c, m, c1, m1 : TMenuItem;
begin
  l := TStringList.Create;
  l.Text := GetCategories(sToDoFOlder);
  View1.Clear;
  CopyItem1.Clear;
  MoveItem1.Clear;
  View1.Visible := False;
  CopyItem1.Visible := False;
  MoveItem1.Visible := False;
  n4.visible := false;
  CopyItem2.Visible := False;
  MoveItem2.Visible := False;
  for x := 0 to l.Count - 1 do
  begin
    if not View1.Visible then
    begin
      View1.Visible := true;
      CopyItem1.Visible := True;
      MoveItem1.Visible := True;
      n4.visible := True;
      CopyItem2.Visible := True;
      MoveItem2.Visible := True;
    end;
    t := TMenuItem.Create(Self);
    c := TMenuItem.Create(Self);
    m := TMenuItem.Create(Self);
    c1 := TMenuItem.Create(Self);
    m1 := TMenuItem.Create(Self);

    t.Name := 'out_t_mnu_' + inttostr(x); //AHRK103
    t.Caption := l.Strings[x];
    t.Visible := true;
    t.OnClick := MenuSelectionClick;

    m.Name := 'out_m_mnu_' + inttostr(x); //AHRK103
    m.Caption := l.Strings[x];
    m.Visible := true;
    m.OnClick := MoveSelectionClick;

    c.Name := 'out_c_mnu_' + inttostr(x); //AHRK103
    c.Caption := l.Strings[x];
    c.Visible := true;
    c.OnClick := CopySelectionClick;

    m1.Name := 'out_m1_mnu_' + inttostr(x); //AHRK103
    m1.Caption := l.Strings[x];
    m1.Visible := true;
    m1.OnClick := MoveSelectionClick;

    c1.Name := 'out_c1_mnu_' + inttostr(x); //AHRK103
    c1.Caption := l.Strings[x];
    c1.Visible := true;
    c1.OnClick := CopySelectionClick;

    View1.Add(t);
    CopyItem1.Add(c);
    MoveItem1.Add(m);
    CopyItem2.Add(c1);
    MoveItem2.Add(m1);
  end;
end;

procedure TToDoEX.DBRefresh(Category : string);
var t : TToDoFile;
    s : TToDoItem;
    x, cntrec : integer;
    l : TListItem;
begin
  t := TToDoFile.Create(sToDoFolder +
    Category + '.ptd', fmOpenRead);
  cntrec := t.Count;
  ListView1.Items.BeginUpdate;
  for x := 1 to cntrec do
  begin
    s := t.ToDoItem[x];
    if not s.Deleted then
    begin
      l := ListView1.Items.Add;
      l.Caption := '';
      l.ImageIndex := -1;

      if s.Priority > 0 then
        l.SubItems.Add(IntToStr(s.Priority))
      else
        l.SubItems.Add('');
      l.SubItems.Add(s.Description);
      if s.StartDate <> 0 then
        l.SubItems.Add(DateTimeToStr(s.StartDate))
      else
        l.SubItems.Add('');

      if s.DueDate <> 0 then
        l.SubItems.Add(DateTimeToStr(s.DueDate))
      else
        l.SubItems.Add('');

      if s.EndDate <> 0 then
      begin
        l.SubItems.Add(DateTimeToStr(s.EndDate));
        l.ImageIndex := 0;
      end
      else
      begin
        l.SubItems.Add('');
        l.ImageIndex := -1;
      end;

      l.SubItems.Add(Category);
      if Trim(s.Notes) <> '' then
        l.SubItems.Add(s.Notes)
      else
        l.SubItems.Add(s.Notes);

      l.SubItems.Add(IntToStr(x));
    end;
    Application.ProcessMessages;
  end;
  t.Free;
  ListView1.Items.EndUpdate;
end;

procedure TToDoEx.ListView1DrawItem(Control: TWinControl;
  var ACanvas: TCanvas; Index: Integer; ARect: TRect;
  State: TOwnerDrawState; var DefaultDrawing, FullRowSelect: Boolean);
begin
  FullRowSelect := True;
  if ListView1.Items[Index].ImageIndex = 0 then
    ACanvas.Font.Style := [fsStrikeOut]
  else
    ACanvas.Font.Style := [];

  if ShowColours1.Checked then
  begin
    if Odd(Index) then
    begin
      ACanvas.Brush.Color := lblEndColor;
    end
    else
    begin
      ACanvas.Brush.Color := lblStartColor;
    end;
  end;
  DefaultDrawing := True;
end;

procedure TToDoEx.dfsGradientFormCreate(Sender: TObject);
var iniFile : tIniFile;
    dbShown : TStringList;
    x : integer;
begin
  SetWindowLong(Handle, GWL_ExStyle, WS_Ex_AppWindow);
  MenuRefresh;
  // Read settings...
  IniFile := TIniFile.Create(sSettingsFile);
  dbShown := TStringList.Create;
  // Load window state...
  case IniFile.ReadInteger('ToDoWindow', 'State', 1) of
  0, 1: begin
      WindowState := wsNormal;
      Width := IniFile.ReadInteger('ToDoWindow', 'ToDoWidth', Width);
      Height := IniFile.ReadInteger('ToDoWindow', 'ToDoHeight', Height);
      Top := IniFile.ReadInteger('ToDoWindow', 'ToDoTop', Top);
      Left := IniFile.ReadInteger('ToDoWindow', 'ToDoTop', Left);
    end;
  2: begin
      WindowState := wsMaximized;
      Top := 0;
      Left := 0;
      Height := screen.DesktopHeight;
      Width := screen.DesktopWidth;
    end;
  end;

  ShowLines1.Checked := IniFile.ReadBool('ToDoWindow', 'ShowLines', False);
  ShowColours1.Checked := IniFile.ReadBool('ToDoWindow', 'ShowColours',
   False);
  ELVReadSettingsFromIniFile(ListView1, 'ToDoWindow', IniFile);
  Panel2.Width := IniFile.ReadInteger('ToDoWindow', 'Splitterpos',
   Panel2.Width);

  dbShown.CommaText := IniFile.ReadString('ToDoWindow', 'DBShown', '');

  for x := 0 to dbShown.Count -1 do
    View1.Items[StrToInt(DbShown.Strings[x])].Checked := True;


  IniFile.Free;
  dbShown.Free;
  UpdateShowLines;
  UpdateList;
end;

procedure TToDoEx.ListView1Click(Sender: TObject);
begin
  UpdateRichEdit;
end;

procedure TToDoEx.actCategoryNewExecute(Sender: TObject);
begin
  NewCategory(sToDoFolder);
  MenuRefresh
end;

procedure TToDoEx.actToDoNewExecute(Sender: TObject);
var x : integer;
    c : string;
begin
  try
    ToDoProperties := TToDoProperties.Create(Self);
    if Assigned(LangHolder) then
    begin
      if LangHolder.Language <> '' then
        LangHolder.Translate([ToDoProperties]);
    end;

    if ListView1.Selected <> nil then
      c := ListView1.Selected.SubItems[siCategory]
    else
    begin
      for x := 0 to View1.Count do
      begin
        if View1.Items[x].Checked then
        begin
          c := StripHotKey(View1.Items[x].Caption);
          break;
        end;
      end;
    end;
    ToDoProperties.ReadFields(-1, c);
    if ToDoProperties.ShowModal = mrOK then
    begin
      ToDoProperties.WriteFields(-1);
    end
  finally
    ToDoProperties.Free;
  end;
  UpdateList;
end;

procedure TToDoEx.actToDoNewUpdate(Sender: TObject);
var r : Boolean;
    x : integer;
begin
  r := False;
  for x := 0 to View1.Count -1 do
  begin
    if View1.Items[x].Checked then
    begin
      r := True;
      break;
    end;
  end;
  (Sender as TAction).Enabled := r;
end;

procedure TToDoEx.actToDoPropertiesExecute(Sender: TObject);
begin
  if (ListView1.SelCount = 1) and (ListView1.Selected <> nil) then
  begin
    try
      ToDoProperties := TToDoProperties.Create(Self);
      if Assigned(LangHolder) then
      begin
        if LangHolder.Language <> '' then
          LangHolder.Translate([ToDoProperties]);
      end;

      ToDoProperties.ReadFields(
        StrToInt(ListView1.Selected.SubItems[siRecordNumber]),
        ListView1.Selected.SubItems[siCategory]);
      if ToDoProperties.ShowModal = mrOK then
      begin
        ToDoProperties.WriteFields(StrToInt(
        ListView1.Selected.SubItems[siRecordNumber]));
      end;
    finally
      ToDoProperties.Free;
    end;
    UpdateList;
  end;
end;

procedure TToDoEx.actToDoDeleteExecute(Sender: TObject);
var l : TListItem;
    r : TToDoFile;
    afile : string;
begin
  afile := '';
  r := nil;
  l := ListView1.Selected;
  while l <> nil do
  begin
    if (afile <> sToDoFolder +  l.SubItems[siCategory] + '.ptd') then
    begin
      afile := sToDoFolder
        +  l.SubItems[siCategory] + '.ptd';
      if Assigned(r) then r.Free;
      r := TToDoFile.Create(afile, fmOpenReadWrite);
    end;

    r.Delete(StrToInt(l.SubItems[siRecordNumber]));
    l := ListView1.GetNextItem(l, sdAll, [isSelected]);
  end;
  // close this one off...
  if Assigned(r) then r.Free;
  UpdateList;
end;

procedure TToDoEx.actToDoDeleteUpdate(Sender: TObject);
begin
  (Sender as TAction).Enabled := (ListView1.Selected <> nil);
end;

procedure TToDoEx.actCloseExecute(Sender: TObject);
begin
  Close;
end;

procedure TToDoEx.actCategoryEditorExecute(Sender: TObject);
var s : tstringlist;
    x : integer;
begin
  CatEditor := TCatEditor.Create(Self);
  if Assigned(LangHolder) then
  begin
    if LangHolder.Language <> '' then
      LangHolder.Translate([CatEditor]);
  end;

  CatEditor.ShowModal;
  s := TStringList.Create;
  if CatEditor.Changed > 0 then
  begin
    for x := 0 to View1.Count -1 do
    begin
      if View1.Items[x].Checked then
        s.Add(StripHotKey(View1.Items[x].Caption));
    end;
    MenuRefresh;
    for x := 0 to View1.Count-1 do
    begin
      if s.IndexOf(StripHotKey(View1.Items[x].Caption)) > -1 then
      begin
        view1.Items[x].Checked := True;
      end;
    end;
    UpdateList;
  end;
  CatEditor.Free;
  s.Free;
end;

procedure TToDoEx.Showlines1Click(Sender: TObject);
begin
  ShowLines1.Checked := not ShowLines1.Checked;
  UpdateShowLines;
end;

procedure TToDoEx.Showcolours1Click(Sender: TObject);
begin
  ShowCOlours1.Checked := not ShowCOlours1.Checked;
  ListView1.Refresh;
end;

procedure TToDoEx.dfsGradientFormDestroy(Sender: TObject);
var IniFile : tIniFile;
    dbShown : TStringList;
    x : integer;
begin
  dbShown := TStringList.Create;
  IniFile := TIniFile.Create(sSettingsFile);
  // Write window state...
  if WindowState = wsNormal then
  begin
    IniFile.WriteInteger('ToDoWindow', 'State', 1);
    IniFile.WriteInteger('ToDoWindow', 'ToDoWidth', Width);
    IniFile.WriteInteger('ToDoWindow', 'ToDoHeight', Height);
    IniFile.WriteInteger('ToDoWindow', 'ToDoTop', Top);
    IniFile.WriteInteger('ToDoWindow', 'ToDoLeft', Left);
  end;

  if WindowState = wsMaximized then
    IniFile.WriteInteger('ToDoWindow', 'ToDoState', 2);

  IniFile.WriteBool('ToDoWindow', 'ShowLines', ShowLines1.Checked);
  IniFile.WriteBool('ToDoWindow', 'ShowColours', ShowColours1.Checked);
  ELVWriteSettingsToIniFile(ListView1, 'ToDoWindow', IniFile);
  IniFile.WriteInteger('ToDoWindow', 'Splitterpos',  Splitter1.Left);


  for x := 0 to View1.Count -1 do
  begin
    if View1.Items[x].Checked then
       dbShown.Add(IntToStr(x));
  end;

  IniFile.WriteString('ToDoWindow', 'DBShown', dbShown.CommaText);

  IniFile.Free;

  dbShown.Free;
  ToDoEx := nil;
end;

procedure TToDoEx.dfsGradientFormShow(Sender: TObject);
begin
  Listview1.Color := MainForm.ListView2.Color;
  ListView1.Font := MainForm.ListView2.Font;
  RichEdit1.Font := MainForm.DefaultFont;
  RichEdit1.Color := MainForm.RichEdit1.Color;
end;

procedure TToDoEx.ListView1SortBegin(Sender: TObject; SortColumn: Integer;
  Ascending: Boolean);
begin
  if SortColumn in [0, 1, 2, 6, 7] then
    ListView1.AutoSortStyle := assDefault
  else
    ListView1.AutoSortStyle := assSmart;
end;

initialization
   PMRegistry.AddCustomClass(TToDoEx, 'TToDoEx');

end.
