{
 ***************************************************************************
 *                                                                         *
 *   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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.   *
 *                                                                         *
 ***************************************************************************

 Author: Balázs Székely
 Abstract:
   Implementation of the main dialog.
}
unit opkman_mainfrm;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, fpjson, md5, Graphics, VirtualTrees,
  // LCL
  Forms, Controls, Dialogs, StdCtrls, ExtCtrls, Buttons, Menus, ComCtrls, Clipbrd,
  LCLIntf, LCLVersion, LCLProc,
  // LazUtils
  LazFileUtils,
  // IdeIntf
  IDECommands, PackageIntf,
  // OpkMan
  opkman_downloader, opkman_installer,
  opkman_serializablepackages, opkman_visualtree, opkman_const, opkman_common,
  opkman_progressfrm, opkman_zipper, opkman_packagelistfrm, opkman_options,
  opkman_optionsfrm, opkman_createrepositorypackagefrm, opkman_updates,
  opkman_createjsonforupdatesfrm, opkman_createrepositoryfrm;

type

  { TMainFrm }

  TMainFrm = class(TForm)
    cbFilterBy: TComboBox;
    cbPackageCategory: TComboBox;
    cbPackageState: TComboBox;
    cbPackageType: TComboBox;
    imTBDis: TImageList;
    miSaveChecked: TMenuItem;
    miFromExteranlSource: TMenuItem;
    miFromRepository: TMenuItem;
    miSaveInstalled: TMenuItem;
    miSep2: TMenuItem;
    miSep3: TMenuItem;
    miSep1: TMenuItem;
    miCreateRepository: TMenuItem;
    miLoad: TMenuItem;
    miSave: TMenuItem;
    miDateDsc: TMenuItem;
    miDateAsc: TMenuItem;
    miNameDsc: TMenuItem;
    miNameAsc: TMenuItem;
    miByDate: TMenuItem;
    miByName: TMenuItem;
    miSaveToFile: TMenuItem;
    miJSONSort: TMenuItem;
    miResetRating: TMenuItem;
    miCopyToClpBrd: TMenuItem;
    miCreateJSONForUpdates: TMenuItem;
    miCreateRepositoryPackage: TMenuItem;
    OD: TOpenDialog;
    pmInstall: TPopupMenu;
    SD: TSaveDialog;
    tbCleanUp1: TToolButton;
    tbInstall1: TToolButton;
    tbUninstall: TToolButton;
    tbOptions: TToolButton;
    cbAll: TCheckBox;
    edFilter: TEdit;
    imTree: TImageList;
    lbFilterBy: TLabel;
    miJSONShow: TMenuItem;
    miJSONHide: TMenuItem;
    mJSON: TMemo;
    pmMemo: TPopupMenu;
    pnFilter: TPanel;
    pnMessage: TPanel;
    pnToolBar: TPanel;
    pnTop: TPanel;
    pnMain: TPanel;
    pmTree: TPopupMenu;
    pmCreate: TPopupMenu;
    SDD: TSelectDirectoryDialog;
    spCollapse: TSpeedButton;
    spClear: TSpeedButton;
    spExpand: TSpeedButton;
    tbButtons: TToolBar;
    imTBNor: TImageList;
    tbDownload: TToolButton;
    tbInstall: TToolButton;
    tbHelp: TToolButton;
    tbRefresh: TToolButton;
    tbCleanUp: TToolButton;
    tbCreate: TToolButton;
    tbUpdate: TToolButton;
    tbOpenRepo: TToolButton;
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure miCopyToClpBrdClick(Sender: TObject);
    procedure miCreateJSONForUpdatesClick(Sender: TObject);
    procedure miCreateRepositoryClick(Sender: TObject);
    procedure miCreateRepositoryPackageClick(Sender: TObject);
    procedure miFromExteranlSourceClick(Sender: TObject);
    procedure miFromRepositoryClick(Sender: TObject);
    procedure miLoadClick(Sender: TObject);
    procedure miNameAscClick(Sender: TObject);
    procedure miResetRatingClick(Sender: TObject);
    procedure miSaveCheckedClick(Sender: TObject);
    procedure miSaveInstalledClick(Sender: TObject);
    procedure miSaveToFileClick(Sender: TObject);
    procedure pnToolBarResize(Sender: TObject);
    procedure tbCleanUpClick(Sender: TObject);
    procedure tbDownloadClick(Sender: TObject);
    procedure tbHelpClick(Sender: TObject);
    procedure tbInstallClick(Sender: TObject);
    procedure tbOpenRepoClick(Sender: TObject);
    procedure tbOptionsClick(Sender: TObject);
    procedure tbRefreshClick(Sender: TObject);
    procedure cbAllClick(Sender: TObject);
    procedure cbFilterByChange(Sender: TObject);
    procedure cbPackageCategoryChange(Sender: TObject);
    procedure cbPackageStateChange(Sender: TObject);
    procedure cbPackageTypeChange(Sender: TObject);
    procedure edFilterChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormKeyPress(Sender: TObject; var Key: char);
    procedure FormShow(Sender: TObject);
    procedure miJSONShowClick(Sender: TObject);
    procedure pnMainResize(Sender: TObject);
    procedure pnTopResize(Sender: TObject);
    procedure spClearClick(Sender: TObject);
    procedure spExpandClick(Sender: TObject);
    procedure tbUninstallClick(Sender: TObject);
    procedure tbUpdateClick(Sender: TObject);
  private
    FHintTimeOut: Integer;
    FFormIsHiden: Boolean;
    procedure EnableDisableControls(const AEnable: Boolean);
    procedure SetupMessage(const AMessage: String = '');
    procedure SetupControls;
    procedure SetupColors;
    procedure GetPackageList(const ARepositoryHasChanged: Boolean = False);
    procedure DoOnChecking(Sender: TObject; const AIsAllChecked: Boolean);
    procedure DoOnChecked(Sender: TObject);
    procedure DoOnJSONProgress(Sender: TObject);
    procedure DoOnJSONDownloadCompleted(Sender: TObject; AJSON: TJSONStringType; AErrTyp: TErrorType; const AErrMsg: String = '');
    procedure DoOnProcessJSON(Sender: TObject);
    procedure DoOnUpdate(Sender: TObject);
    procedure DoDeactivate(Sender: TObject);
    function IsSomethingChecked(const AResolveDependencies: Boolean = True): Boolean;
    function Download(const ADstDir: String; var ADoExtract: Boolean): TModalResult;
    function Extract(const ASrcDir, ADstDir: String; var ADoOpen: Boolean; const AIsUpdate: Boolean = False): TModalResult;
    function Install(var AInstallStatus: TInstallStatus; var ANeedToRebuild: Boolean): TModalResult;
    function UpdateP(const ADstDir: String; var ADoExtract: Boolean): TModalResult;
    procedure StartUpdates;
    procedure StopUpdates;
    procedure Rebuild;
    function CheckDstDir(const ADstDir: String): Boolean;
  public
    procedure ShowOptions(const AActivePageIndex: Integer = 0);
  end;

var
  MainFrm: TMainFrm;

implementation

{$R *.lfm}

{ TMainFrm }

procedure TMainFrm.FormCreate(Sender: TObject);
begin
  VisualTree := TVisualTree.Create(pnMain, imTree, pmTree);
  VisualTree.OnChecking := @DoOnChecking;
  VisualTree.OnChecked := @DoOnChecked;
  SerializablePackages.OnProcessJSON := @DoOnProcessJSON;
  PackageDownloader.OnJSONProgress := @DoOnJSONProgress;
  PackageDownloader.OnJSONDownloadCompleted := @DoOnJSONDownloadCompleted;
  FHintTimeOut := Application.HintHidePause;
  Application.HintHidePause := 1000000;
  Application.AddOnDeactivateHandler(@DoDeactivate, False);
 {$IF LCL_FULLVERSION >= 1070000}
  tbInstall.Style := tbsButtonDrop;
  tbCreate.Style := tbsButtonDrop;
 {$ENDIF}
end;

procedure TMainFrm.StartUpdates;
var
  FileName: String;
begin
  FileName := Format(LocalRepositoryUpdatesFile, [MD5Print(MD5String(Options.RemoteRepository[Options.ActiveRepositoryIndex]))]);
  Updates := TUpdates.Create(FileName);
  Updates.OnUpdate := @DoOnUpdate;
  Updates.StartUpdate;
end;

procedure TMainFrm.StopUpdates;
begin
  if Assigned(Updates) then
  begin
    Updates.StopUpdate;
    Updates.Terminate;
    Updates := nil;
  end;
end;

procedure TMainFrm.FormDestroy(Sender: TObject);
begin
  SerializablePackages.OnProcessJSON := nil;
  PackageDownloader.OnJSONProgress := nil;
  PackageDownloader.OnJSONDownloadCompleted := nil;
  StopUpdates;
  Application.RemoveOnDeactivateHandler(@DoDeactivate);
  VisualTree.Free;
  Application.HintHidePause := FHintTimeOut;
end;

procedure TMainFrm.FormKeyPress(Sender: TObject; var Key: char);
begin
  if Key = #27 then
    Close;
end;

procedure TMainFrm.FormShow(Sender: TObject);
begin
  if not FFormIsHiden then
  begin
    SetupControls;
    SetupColors;
    GetPackageList;
  end
  else
    if not Application.Terminated then
      StartUpdates;
end;

procedure TMainFrm.GetPackageList(const ARepositoryHasChanged: Boolean = False);
begin
  cbFilterBy.ItemIndex := 0;
  cbFilterByChange(cbFilterBy);
  Caption := rsLazarusPackageManager;
  EnableDisableControls(False);
  VisualTree.VST.Clear;
  VisualTree.VST.Invalidate;
  if ARepositoryHasChanged then
  begin
    SetupMessage(rsMainFrm_rsMessageChangingRepository);
    Sleep(1500);
  end;
  StopUpdates;
  SetupMessage(rsMainFrm_rsMessageDownload);
  PackageDownloader.DownloadJSON(Options.ConTimeOut*1000);
end;

function TMainFrm.IsSomethingChecked(const AResolveDependencies: Boolean = True): Boolean;
begin
  Result := VisualTree.VST.CheckedCount > 0;
  if Result then
  begin
    if AResolveDependencies then
      if VisualTree.ResolveDependencies = mrCancel then
      begin
        Result := False;
        Exit;
      end;
    VisualTree.GetPackageList;
    VisualTree.UpdatePackageStates;
  end
  else
    MessageDlgEx(rsMainFrm_rsNoPackageToDownload, mtInformation, [mbOk], Self)
end;

function TMainFrm.CheckDstDir(const ADstDir: String): Boolean;
begin
  Result := True;
  if not DirectoryExists(ADstDir) then
  begin
    if not ForceDirectories(ADstDir) then
    begin
      MessageDlgEx(Format(rsMainFrm_rsDestDirError, [ADstDir]), mtError, [mbOk], Self);
      Result := False;
    end;
  end;
end;


function TMainFrm.Download(const ADstDir: String; var ADoExtract: Boolean): TModalResult;
begin
  if not CheckDstDir(ADstDir) then
  begin
    Result := mrCancel;
    Exit;
  end;
  ADoExtract := False;
  ProgressFrm := TProgressFrm.Create(MainFrm);
  try
    ProgressFrm.SetupControls(0);
    PackageDownloader.OnPackageDownloadProgress := @ProgressFrm.DoOnPackageDownloadProgress;
    PackageDownloader.OnPackageDownloadError := @ProgressFrm.DoOnPackageDownloadError;
    PackageDownloader.OnPackageDownloadCompleted := @ProgressFrm.DoOnPackageDownloadCompleted;
    PackageDownloader.DownloadPackages(ADstDir);
    Result := ProgressFrm.ShowModal;
    if Result = mrOK then
      ADoExtract := ProgressFrm.cbExtractOpen.Checked;
  finally
    ProgressFrm.Free;
  end;
end;

function TMainFrm.Extract(const ASrcDir, ADstDir: String; var ADoOpen: Boolean;
  const AIsUpdate: Boolean = False): TModalResult;
begin
  if not CheckDstDir(ADstDir) then
  begin
    Result := mrCancel;
    Exit;
  end;
  ProgressFrm := TProgressFrm.Create(MainFrm);
  try
    PackageUnzipper := TPackageUnzipper.Create;
    try
      ProgressFrm.SetupControls(1);
      PackageUnzipper.OnZipProgress := @ProgressFrm.DoOnZipProgress;
      PackageUnzipper.OnZipError := @ProgressFrm.DoOnZipError;
      PackageUnzipper.OnZipCompleted := @ProgressFrm.DoOnZipCompleted;
      PackageUnzipper.StartUnZip(ASrcDir, ADstDir, AIsUpdate);
      Result := ProgressFrm.ShowModal;
      if Result = mrOk then
        ADoOpen := ProgressFrm.cbExtractOpen.Checked;
    finally
      if Assigned(PackageUnzipper) then
        PackageUnzipper := nil;
    end;
 finally
   ProgressFrm.Free;
 end;
end;

function TMainFrm.Install(var AInstallStatus: TInstallStatus;
  var ANeedToRebuild: Boolean): TModalResult;
begin
  ProgressFrm := TProgressFrm.Create(MainFrm);
  try
    ProgressFrm.SetupControls(2);
    Result := ProgressFrm.ShowModal;
    if Result = mrOk then
    begin
      AInstallStatus := ProgressFrm.InstallStatus;
      ANeedToRebuild := ProgressFrm.NeedToRebuild;
    end;
  finally
    ProgressFrm.Free;
  end;
end;

function TMainFrm.UpdateP(const ADstDir: String; var ADoExtract: Boolean): TModalResult;
begin
  if not CheckDstDir(ADstDir) then
   begin
     Result := mrCancel;
     Exit;
   end;
  ADoExtract := False;
  ProgressFrm := TProgressFrm.Create(MainFrm);
  try
    ProgressFrm.SetupControls(3);
    PackageDownloader.OnPackageDownloadProgress := @ProgressFrm.DoOnPackageDownloadProgress;
    PackageDownloader.OnPackageDownloadError := @ProgressFrm.DoOnPackageDownloadError;
    PackageDownloader.OnPackageDownloadCompleted := @ProgressFrm.DoOnPackageDownloadCompleted;
    PackageDownloader.OnPackageUpdateProgress := @ProgressFrm.DoOnPackageUpdateProgress;
    PackageDownloader.OnPackageUpdateCompleted := @ProgressFrm.DoOnPackageUpdateCompleted;
    PackageDownloader.UpdatePackages(ADstDir);
    Result := ProgressFrm.ShowModal;
    if Result = mrOK then
      ADoExtract := ProgressFrm.cbExtractOpen.Checked;
  finally
    ProgressFrm.Free;
  end;
end;

procedure TMainFrm.DoOnJSONDownloadCompleted(Sender: TObject; AJSON: TJSONStringType; AErrTyp: TErrorType; const AErrMsg: String = '');
begin
  case AErrTyp of
    etNone:
      begin
        SetupMessage(rsMainFrm_rsMessageParsingJSON);
        if (SerializablePackages.Count = 0) then
        begin
          EnableDisableControls(True);
          SetupMessage(rsMainFrm_rsMessageNoPackage);
          MessageDlgEx(rsMainFrm_rsMessageError1 + sLineBreak + SerializablePackages.LastError, mtInformation, [mbOk], Self);
          Exit;
        end;
        VisualTree.PopulateTree;
        EnableDisableControls(True);
        SetupMessage;
        mJSON.Text := AJSON;
        StartUpdates;
        cbAll.Checked := False;
        Caption := rsLazarusPackageManager + ' ' + SerializablePackages.QuickStatistics;
      end;
    etConfig:
      begin
        EnableDisableControls(True);
        SetupMessage(rsMainFrm_rsMessageNoPackage);
        Caption := rsLazarusPackageManager;
        if MessageDlgEx('"' + AErrMsg + '"', mtConfirmation, [mbYes, mbNo], Self) = mrYes then
          ShowOptions;
      end;
    etTimeOut, etHTTPClient:
      begin
        EnableDisableControls(True);
        SetupMessage(rsMainFrm_rsMessageNoPackage);
        Caption := rsLazarusPackageManager;
        MessageDlgEx(rsMainFrm_rsMessageError0 + sLineBreak + '"' + AErrMsg + '"', mtInformation, [mbOk], Self);
      end;
  end;
end;

procedure TMainFrm.DoOnJSONProgress(Sender: TObject);
begin
  Application.ProcessMessages;
end;


procedure TMainFrm.DoOnProcessJSON(Sender: TObject);
begin
  Application.ProcessMessages;
end;

procedure TMainFrm.DoOnUpdate(Sender: TObject);
begin
  VisualTree.UpdatePackageUStatus;
end;

procedure TMainFrm.DoDeactivate(Sender: TObject);
begin
  if Assigned(VisualTree.ShowHintFrm) then
    if VisualTree.ShowHintFrm.Visible then
       VisualTree.ShowHintFrm.Hide;
end;

procedure TMainFrm.ShowOptions(const AActivePageIndex: Integer = 0);
var
  OldIndex: Integer;
  DefaultTheme: Boolean;
begin
  OptionsFrm := TOptionsFrm.Create(MainFrm);
  try
    OptionsFrm.SetupControls(AActivePageIndex);
    OldIndex := Options.ActiveRepositoryIndex;
    DefaultTheme := Options.UseDefaultTheme;
    if OptionsFrm.ShowModal = mrOk then
    begin
      tbRefresh.Enabled := Trim(Options.RemoteRepository[Options.ActiveRepositoryIndex]) <> '';
      GetPackageList(OldIndex <> Options.ActiveRepositoryIndex);
      if DefaultTheme <> Options.UseDefaultTheme then
        SetupColors;
    end;
  finally
    OptionsFrm.Free;
  end;
end;

procedure TMainFrm.EnableDisableControls(const AEnable: Boolean);
begin
  cbAll.Enabled := (AEnable) and (SerializablePackages.Count > 0);
  cbFilterBy.Enabled := (AEnable) and (SerializablePackages.Count > 0);
  pnFilter.Enabled := (AEnable) and (SerializablePackages.Count > 0);
  cbPackageState.Enabled := (AEnable) and (SerializablePackages.Count > 0);
  cbPackageType.Enabled := (AEnable) and (SerializablePackages.Count > 0);

  spExpand.Enabled := (AEnable) and (SerializablePackages.Count > 0);
  spCollapse.Enabled := (AEnable) and (SerializablePackages.Count > 0);
  VisualTree.VST.Enabled := (AEnable) and (SerializablePackages.Count > 0);
  if edFilter.CanFocus then
    edFilter.SetFocus;
  tbRefresh.Enabled := (AEnable) and (Trim(Options.RemoteRepository[Options.ActiveRepositoryIndex]) <> '');
  tbDownload.Enabled := (AEnable) and (SerializablePackages.Count > 0) and (VisualTree.VST.CheckedCount > 0);
  tbInstall.Enabled := (AEnable) and (SerializablePackages.Count > 0) and (VisualTree.VST.CheckedCount > 0);
  tbUninstall.Enabled := (AEnable) and (SerializablePackages.Count > 0) and (VisualTree.VST.CheckedCount > 0);
  tbUpdate.Enabled :=  (AEnable) and (SerializablePackages.Count > 0) and (VisualTree.VST.CheckedCount > 0);
  tbOpenRepo.Enabled := (AEnable);
  tbCleanUp.Enabled := (AEnable) and (SerializablePackages.Count > 0);
  tbCreate.Visible := Options.UserProfile = 1;
  if tbCreate.Visible then
  begin
    tbCreate.Left := tbOptions.Left - 10;
    tbCreate.Enabled := (AEnable);
  end;
  pnToolBarResize(pnToolbar);
  tbOptions.Enabled := (AEnable);
  tbHelp.Enabled := (AEnable);
end;

procedure TMainFrm.SetupMessage(const AMessage: String = '');
begin
  if AMessage = '' then
  begin
    pnMessage.SendToBack;
    pnMessage.Visible := False;
  end
  else
  begin
    pnMessage.Caption := AMessage;
    pnMessage.Visible := True;
    pnMessage.BringToFront;
    Application.ProcessMessages;
  end;
end;

procedure TMainFrm.DoOnChecking(Sender: TObject; const AIsAllChecked: Boolean);
begin
  cbAll.OnClick := nil;
  cbAll.Checked := AIsAllChecked;
  cbAll.OnClick := @cbAllClick;
end;

procedure TMainFrm.DoOnChecked(Sender: TObject);
begin
  EnableDisableControls(True);
end;

procedure TMainFrm.cbAllClick(Sender: TObject);
begin
  VisualTree.CheckNodes(cbAll.Checked);
  EnableDisableControls(True);
end;

procedure TMainFrm.cbFilterByChange(Sender: TObject);
begin
  VisualTree.ResetFilter;
  case cbFilterBy.ItemIndex of
    0..1, 4..9, 11..12:
      begin
        cbPackageType.Visible := False;
        cbPackageState.Visible := False;
        cbPackageCategory.Visible := False;
        pnFilter.Visible := True;
        edFilter.Text := '';
        if edFilter.CanFocus then
          edFilter.SetFocus;
      end;
   2: begin
        pnFilter.Visible := False;
        cbPackageType.Visible := False;
        cbPackageState.Visible := False;
        cbPackageCategory.Visible := True;
        cbPackageCategory.ItemIndex := 0;
        if cbPackageCategory.CanFocus then
          cbPackageCategory.SetFocus;
      end;
   3: begin
        pnFilter.Visible := False;
        cbPackageType.Visible := False;
        cbPackageState.Visible := True;
        cbPackageCategory.Visible := False;
        cbPackageState.ItemIndex := 0;
        if cbPackageState.CanFocus then
          cbPackageState.SetFocus;
      end;
   10: begin
        pnFilter.Visible := False;
        cbPackageState.Visible := False;
        cbPackageType.Visible := True;
        cbPackageCategory.Visible := False;
        cbPackageType.ItemIndex := 0;
        if cbPackageType.CanFocus then
          cbPackageType.SetFocus;
      end;
  end;
  cbPackageState.Height := cbFilterBy.Height;
  cbPackageState.Top := (pnTop.Height - cbPackageState.Height) div 2;
  cbPackageType.Height := cbFilterBy.Height;
  cbPackageType.Top := (pnTop.Height - cbPackageType.Height) div 2;
  cbPackageCategory.Height := cbFilterBy.Height;
  cbPackageCategory.Top := (pnTop.Height - cbPackageCategory.Height) div 2;
end;

procedure TMainFrm.cbPackageCategoryChange(Sender: TObject);
begin
  if cbPackageCategory.ItemIndex > 0 then
    VisualTree.FilterTree(TFilterBy(cbFilterBy.ItemIndex), 'PackageCategory', cbPackageCategory.ItemIndex - 1)
  else
    VisualTree.ResetFilter;
end;

procedure TMainFrm.cbPackageTypeChange(Sender: TObject);
begin
  if cbPackageType.ItemIndex > 0 then
    VisualTree.FilterTree(TFilterBy(cbFilterBy.ItemIndex), 'PackageType', cbPackageType.ItemIndex - 1)
  else
    VisualTree.ResetFilter;
end;

procedure TMainFrm.cbPackageStateChange(Sender: TObject);
begin
  if cbPackageState.ItemIndex > 0 then
    VisualTree.FilterTree(TFilterBy(cbFilterBy.ItemIndex), 'PackageState', cbPackageState.ItemIndex - 1)
  else
    VisualTree.ResetFilter;
end;

procedure TMainFrm.edFilterChange(Sender: TObject);
begin
  if edFilter.Text <> '' then
    VisualTree.FilterTree(TFilterBy(cbFilterBy.ItemIndex), edFilter.Text)
  else
    VisualTree.ResetFilter;
end;

procedure TMainFrm.pnTopResize(Sender: TObject);
begin
  cbFilterBy.Left := (pnTop.Width - pnFilter.Width - cbFilterBy.Width + lbFilterBy.Width - 5) div 2;
  pnFilter.Left := cbFilterBy.Left + cbFilterBy.Width + 5;
  cbPackageType.Left := pnFilter.Left;
  cbPackageState.Left := pnFilter.Left;
  cbPackageCategory.Left := pnFilter.Left;
  lbFilterBy.Left := cbFilterBy.Left - 8 - lbFilterBy.Width;
end;

procedure TMainFrm.spClearClick(Sender: TObject);
begin
  edFilter.OnChange := nil;
  edFilter.Text := '';
  VisualTree.ResetFilter;
  edFilter.OnChange := @edFilterChange;
end;

procedure TMainFrm.spExpandClick(Sender: TObject);
begin
  case TSpeedButton(Sender).Tag of
    1: VisualTree.ExpandEx;
    2: VisualTree.CollapseEx;
  end;
end;

procedure TMainFrm.tbOptionsClick(Sender: TObject);
begin
  ShowOptions;
end;

procedure TMainFrm.tbHelpClick(Sender: TObject);
begin
  OpenURL('http://wiki.freepascal.org/Online_Package_Manager');
end;

procedure TMainFrm.tbRefreshClick(Sender: TObject);
begin
  GetPackageList;
end;

procedure TMainFrm.tbDownloadClick(Sender: TObject);
var
  DstDir: String;
  CanGo: Boolean;
  DoExtract: Boolean;
  DoOpen: Boolean;
begin
  if not IsSomethingChecked(False) then
    Exit;

  SDD.InitialDir := Options.LastDownloadDir;
  if SDD.Execute then
  begin
    CanGo := True;
    DstDir := AppendPathDelim(SDD.FileName);
    VisualTree.UpdatePackageStates;
    PackageListFrm := TPackageListFrm.Create(MainFrm);
    try
      PackageListFrm.lbMessage.Caption := rsMainFrm_PackageAlreadyDownloaded;
      PackageListFrm.PopulateList(1, DstDir);
      if PackageListFrm.Count > 0 then
        CanGo := PackageListFrm.ShowModal = mrYes
      else
        CanGo := True;
    finally
      PackageListFrm.Free;
    end;
  end
  else
    CanGo := False;

  if CanGo then
  begin
    StopUpdates;
    Options.LastDownloadDir := DstDir;
    Options.Changed := True;
    PackageAction := paDownloadTo;
    DoExtract := False;
    if Download(DstDir, DoExtract) = mrOK then
    begin
      if SerializablePackages.ExtractCount > 0 then
      begin
        if DoExtract then
        begin
          DoOpen := False;
          if Extract(DstDir, DstDir, DoOpen) = mrOk then
          begin
            if DoOpen then
              OpenDocument(DstDir);
          end;
        end;
      end;
    end;
  end;
  SerializablePackages.RemoveErrorState;
  StartUpdates;
end;

procedure TMainFrm.Rebuild;
begin
  FFormIsHiden := True;
  Self.Hide;
  IDECommands.ExecuteIDECommand(Self, ecBuildLazarus);
  Self.Show;
  FFormIsHiden := False;
end;

procedure TMainFrm.tbUpdateClick(Sender: TObject);
var
  CanGo: Boolean;
  DoOpen: Boolean;
  DoExtract: Boolean;
  InstallStatus: TInstallStatus;
  NeedToRebuild: Boolean;
begin
  if not IsSomethingChecked(False) then
    Exit;
  CanGo := True;
  NeedToRebuild := False;
  VisualTree.UpdatePackageStates;
  PackageListFrm := TPackageListFrm.Create(MainFrm);
  try
    PackageListFrm.lbMessage.Caption := rsMainFrm_PackageUpdate0;
    PackageListFrm.PopulateList(2);
    if PackageListFrm.Count > 0 then
      CanGo := PackageListFrm.ShowModal = mrYes
    else
      CanGo := True;
  finally
    PackageListFrm.Free;
  end;

  if CanGo then
  begin
    if MessageDlgEx(rsMainFrm_PackageUpdateWarning, mtConfirmation, [mbYes, mbNo], Self) <> mrYes then
      Exit;

    StopUpdates;
    PackageAction := paUpdate;
    VisualTree.UpdatePackageStates;
    if SerializablePackages.DownloadCount > 0 then
    begin
      DoExtract := True;
      CanGo := UpdateP(Options.LocalRepositoryUpdateExpanded, DoExtract) = mrOK;
      VisualTree.UpdatePackageStates;
    end;

    if CanGo then
    begin
      if SerializablePackages.ExtractCount > 0 then
      begin
        DoOpen := False;
        CanGo := Extract(Options.LocalRepositoryUpdateExpanded, Options.LocalRepositoryPackagesExpanded, DoOpen, True) = mrOk;
        VisualTree.UpdatePackageStates;
      end;

      if CanGo then
      begin
        if Options.DeleteZipAfterInstall then
          SerializablePackages.DeleteDownloadedZipFiles;
        if SerializablePackages.InstallCount > 0 then
        begin
          InstallStatus := isFailed;
          if Install(InstallStatus, NeedToRebuild) = mrOk then
          begin
            if (InstallStatus = isSuccess) or (InstallStatus = isPartiallyFailed) then
            begin
              SerializablePackages.MarkRuntimePackages;
              VisualTree.UpdatePackageStates;
              if NeedToRebuild then
                Rebuild;
            end;
          end;
        end;
      end;
    end;
  end;
  if not NeedToRebuild then
  begin
    SerializablePackages.RemoveErrorState;
    StartUpdates;
  end;
end;

procedure TMainFrm.tbUninstallClick(Sender: TObject);

  function IsAtLeastOnePackageInstalled: Boolean;
  var
    I, J: Integer;
    LazarusPackage: TLazarusPackage;
  begin
    Result := False;
    for I := 0 to SerializablePackages.Count - 1 do
    begin
      for J := 0 to SerializablePackages.Items[I].LazarusPackages.Count - 1 do
      begin
        LazarusPackage := TLazarusPackage(SerializablePackages.Items[I].LazarusPackages.Items[J]);
        if (LazarusPackage.Checked) and (LazarusPackage.PackageState = psInstalled) then
        begin
          Result := True;
          Exit;
        end;
      end;
    end;
  end;

  function GetIDEPackage(const AFileName: String): TIDEPackage;
  var
    I: Integer;
    IDEPackge: TIDEPackage;
  begin
    Result := nil;
    for I := 0 to PackageEditingInterface.GetPackageCount - 1 do
    begin
      IDEPackge := PackageEditingInterface.GetPackages(I);
      if UpperCase(IDEPackge.Filename) = UpperCase(AFileName) then
      begin
        Result := IDEPackge;
        Break;
      end;
    end;
  end;

var
  I, J: Integer;
  LazarusPackage: TLazarusPackage;
  IDEPackage: TIDEPackage;
  FileName: String;
  NeedToRebuild: Boolean;
begin
  if not IsSomethingChecked(False) then
    Exit;

   if IsAtLeastOnePackageInstalled then
   begin
     if MessageDlgEx(Format(rsMainFrm_rsUninstall, ['             ']), mtInformation, [mbYes, mbNo], Self) <> mrYes then
       Exit;
   end
   else
   begin
     MessageDlgEx(rsMainFrm_rsUninstall_Nothing, mtInformation, [mbOk], Self);
     Exit;
   end;

  NeedToRebuild := False;
  StopUpdates;
  for I := 0 to SerializablePackages.Count - 1 do
  begin
    for J := 0 to SerializablePackages.Items[I].LazarusPackages.Count - 1 do
    begin
      LazarusPackage := TLazarusPackage(SerializablePackages.Items[I].LazarusPackages.Items[J]);
      if (LazarusPackage.Checked) and (LazarusPackage.PackageState = psInstalled) then
      begin
        case LazarusPackage.PackageType of
          lptRunTime, lptRunTimeOnly:
          begin
            FileName := StringReplace(LazarusPackage.Name, '.lpk', '.opkman', [rfIgnoreCase]);
            if FileExists(Options.LocalRepositoryPackagesExpanded + SerializablePackages.Items[I].PackageBaseDir + LazarusPackage.PackageRelativePath + FileName) then
              DeleteFile(Options.LocalRepositoryPackagesExpanded + SerializablePackages.Items[I].PackageBaseDir + LazarusPackage.PackageRelativePath + FileName);
            NeedToRebuild := True;
          end;
          lptDesignTime, lptRunAndDesignTime:
          begin
            IDEPackage := GetIDEPackage(LazarusPackage.InstalledFileName);
            if IDEPackage <> nil then
            begin
              if PackageEditingInterface.UninstallPackage(IDEPackage, False) <> mrOk then
              begin
                NeedToRebuild := False;
                MessageDlgEx(Format(rsMainFrm_rsUninstall_Error, [LazarusPackage.Name]), mtError, [mbOk], Self);
                StartUpdates;
                Exit;
              end
              else
                NeedToRebuild := True;
            end;
          end;
        end;
      end;
    end;
  end;
  if NeedToRebuild then
    Rebuild;
end;

procedure TMainFrm.tbInstallClick(Sender: TObject);
var
  CanGo: Boolean;
  DoExtract: Boolean;
  DoOpen: Boolean;
  InstallStatus: TInstallStatus;
  NeedToRebuild: Boolean;
begin
  if not IsSomethingChecked then
    Exit;

  CanGo := True;
  PackageListFrm := TPackageListFrm.Create(MainFrm);
  try
    PackageListFrm.lbMessage.Caption := rsMainFrm_PackageAlreadyInstalled;
    PackageListFrm.PopulateList(0);
    if PackageListFrm.Count > 0 then
      CanGo := PackageListFrm.ShowModal = mrYes
    else
      CanGo := True;
  finally
    PackageListFrm.Free;
  end;

  if CanGo then
  begin
    StopUpdates;
    PackageAction := paInstall;
    VisualTree.UpdatePackageStates;
    if SerializablePackages.DownloadCount > 0 then
    begin
      DoExtract := True;
      CanGo := Download(Options.LocalRepositoryArchiveExpanded, DoExtract) = mrOK;
      VisualTree.UpdatePackageStates;
    end;

    if CanGo then
    begin
      if SerializablePackages.ExtractCount > 0 then
      begin
        DoOpen := False;
        CanGo := Extract(Options.LocalRepositoryArchiveExpanded, Options.LocalRepositoryPackagesExpanded, DoOpen) = mrOk;
        VisualTree.UpdatePackageStates;
      end;

      if CanGo then
      begin
        if Options.DeleteZipAfterInstall then
          SerializablePackages.DeleteDownloadedZipFiles;
        if SerializablePackages.InstallCount > 0 then
        begin
          InstallStatus := isFailed;
          NeedToRebuild := False;
          if Install(InstallStatus, NeedToRebuild) = mrOk then
          begin
            SerializablePackages.MarkRuntimePackages;
            VisualTree.UpdatePackageStates;
            if (InstallStatus = isSuccess) or (InstallStatus = isPartiallyFailed) then
              if NeedToRebuild then
                Rebuild;
          end;
        end;
      end;
    end;
  end;
  if not NeedToRebuild then
  begin
    SerializablePackages.RemoveErrorState;
    StartUpdates;
  end;
end;

procedure TMainFrm.miFromRepositoryClick(Sender: TObject);
begin
  tbInstallClick(tbInstall);
end;

procedure TMainFrm.miFromExteranlSourceClick(Sender: TObject);
begin
  tbUpdateClick(tbUpdate);
end;


procedure TMainFrm.tbOpenRepoClick(Sender: TObject);
begin
  OpenDocument(Options.LocalRepositoryPackagesExpanded);
end;

procedure TMainFrm.tbCleanUpClick(Sender: TObject);
var
  Cnt: Integer;
begin
  if MessageDlgEx(rsMainFrm_rsRepositoryCleanup0, mtInformation, [mbYes, mbNo], Self) = mrYes then
  begin
    Screen.Cursor := crHourGlass;
    try
      Cnt := SerializablePackages.Cleanup;
    finally
      Screen.Cursor := crDefault;
    end;
    MessageDlgEx(Format(rsMainFrm_rsRepositoryCleanup1, [IntToStr(Cnt)]),
      mtInformation, [mbOk], Self);
  end;
end;

procedure TMainFrm.pnToolBarResize(Sender: TObject);
var
  I: Integer;
  W: Integer;
begin
  W := 0;
  for I := 0 to tbButtons.ButtonCount - 1 do
    if tbButtons.Buttons[I].Visible then
      W := W + tbButtons.Buttons[I].Width;
  tbButtons.Width := W + 2;
  if tbButtons.Width < 450 then
    tbButtons.Width := 450;
  tbButtons.Left := (pnToolBar.Width - tbButtons.Width) div 2;
  tbButtons.Height := tbButtons.Buttons[0].Height;
  tbButtons.Top := (pnToolBar.Height - tbButtons.Height) div 2;
end;

procedure TMainFrm.miCreateRepositoryPackageClick(Sender: TObject);
begin
  CreateRepositoryPackagesFrm := TCreateRepositoryPackagesFrm.Create(MainFrm);
  try
    CreateRepositoryPackagesFrm.SetType(0);
    CreateRepositoryPackagesFrm.ShowModal;
  finally
    CreateRepositoryPackagesFrm.Free;
  end;
end;

procedure TMainFrm.miCreateJSONForUpdatesClick(Sender: TObject);
var
  Msg: String;
begin
  case VisualTree.GetCheckedRepositoryPackages of
    0: Msg := rsCreateJSONForUpdatesFrm_Message0;
    1: Msg := '';
    2: Msg := rsCreateJSONForUpdatesFrm_Message1;
  end;
  if Msg <> '' then
  begin
    MessageDlgEx(Msg, mtInformation, [mbOk], MainFrm);
    Exit;
  end;
  VisualTree.GetPackageList;
  CreateJSONForUpdatesFrm := TCreateJSONForUpdatesFrm.Create(MainFrm);
  try
    CreateJSONForUpdatesFrm.PopluateTree;
    CreateJSONForUpdatesFrm.ShowModal;
  finally
    CreateJSONForUpdatesFrm.Free;
  end;
end;

procedure TMainFrm.miCreateRepositoryClick(Sender: TObject);
var
  CreateRepositoryFrm: TCreateRepositoryFrm;
begin
  CreateRepositoryFrm := TCreateRepositoryFrm.Create(MainFrm);
  try
    CreateRepositoryFrm.ShowModal;
  finally
    CreateRepositoryFrm.Free;
  end;
end;

procedure TMainFrm.miCopyToClpBrdClick(Sender: TObject);
var
  Data: PData;
  Node: PVirtualNode;
begin
  Node := VisualTree.VST.GetFirstSelected;
  if Node <> nil then
  begin
    Data := VisualTree.VST.GetNodeData(Node);
    case Data^.DataType of
      17: Clipboard.AsText := Data^.HomePageURL;
      18: Clipboard.AsText := Data^.DownloadURL;
    end;
  end;
end;

procedure TMainFrm.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if ssCtrl in Shift then
  begin
    if (Key = 82) and (tbRefresh.Enabled) then
      tbRefreshClick(tbRefresh)
    else if (Key = 68) and (tbDownload.Enabled) then
      tbDownloadClick(tbDownload)
    else if (Key = 73) and (tbInstall.Enabled) then
      tbInstallClick(tbInstall)
    else if (Key = 69) and (tbUpdate.Enabled) then
      tbUpdateClick(tbUpdate)
    else if (Key = 85) and (tbUninstall.Enabled) then
      tbUninstallClick(tbUninstall)
    else if (Key = 76) and (tbOpenRepo.Enabled) then
      tbOpenRepoClick(tbOpenRepo)
    else if (Key = 67) and (tbCleanUp.Enabled) then
      tbCleanUpClick(tbCleanUp)
    else if (Key = 80) and (tbInstall.Enabled) then
      miCreateRepositoryPackageClick(miCreateRepositoryPackage)
    else if (Key = 79) and (tbOptions.Enabled) then
      tbOptionsClick(tbOptions)
    else if (Key = 72) and (tbHelp.Enabled) then
      tbHelpClick(tbHelp);
  end;
end;

procedure TMainFrm.miResetRatingClick(Sender: TObject);
var
  Data: PData;
  Node: PVirtualNode;
  MetaPkg: TMetaPackage;
begin
  if MessageDlgEx(rsMainFrm_miResetRating + '?', mtConfirmation, [mbYes, mbNo], Self) = mrNo then
    Exit;
  Node := VisualTree.VST.GetFirstSelected;
  if Node <> nil then
  begin
    Data := VisualTree.VST.GetNodeData(Node);
    if Data^.DataType = 1 then
    begin
      Data^.Rating := 0;
      MetaPkg := SerializablePackages.FindMetaPackage(Data^.PackageName, fpbPackageName);
      if MetaPkg <> nil then
        MetaPkg.Rating := 0;
      VisualTree.VST.ReinitNode(Node, False);
      VisualTree.VST.RepaintNode(Node);
    end;
  end;
end;

procedure TMainFrm.miSaveCheckedClick(Sender: TObject);
var
  Node: PVirtualNode;
  Data: PData;
  SL: TStringList;
begin
  SD.DefaultExt := '.*.opm';
  SD.Filter := '*.opm|*.opm';

  SL := TStringList.Create;
  try
    Node := VisualTree.VST.GetFirst;
    while Node <> nil do
    begin
      if VisualTree.VST.CheckState[Node] = csCheckedNormal then
      begin
        Data := VisualTree.VST.GetNodeData(Node);
        if (Data^.DataType = 2) then
          SL.Add(Data^.LazarusPackageName);
      end;
      Node := VisualTree.VST.GetNext(Node);
    end;
    if Trim(SL.Text) = '' then
      MessageDlgEx(rsMainFrm_rsMessageNothingChacked, mtInformation, [mbOk], Self)
    else
      if SD.Execute then
      begin
         SL.SaveToFile(SD.FileName);
         MessageDlgEx(Format(rsMainFrm_resMessageChecksSaved, [IntToStr(SL.Count)]), mtInformation, [mbOk], Self)
      end;
  finally
    SL.Free;
  end;
end;

procedure TMainFrm.miSaveInstalledClick(Sender: TObject);
var
  Node: PVirtualNode;
  Data: PData;
  SL: TStringList;
begin
  SD.DefaultExt := '.*.opm';
  SD.Filter := '*.opm|*.opm';

  SL := TStringList.Create;
  try
    Node := VisualTree.VST.GetFirst;
    while Node <> nil do
    begin
      Data := VisualTree.VST.GetNodeData(Node);
      if (Data^.DataType = 2) and (Data^.InstalledVersion <> '') then
        SL.Add(Data^.LazarusPackageName);
      Node := VisualTree.VST.GetNext(Node);
    end;
    if Trim(SL.Text) = '' then
      MessageDlgEx(rsMainFrm_rsMessageNothingInstalled, mtInformation, [mbOk], Self)
    else
      if SD.Execute then
      begin
         SL.SaveToFile(SD.FileName);
         MessageDlgEx(Format(rsMainFrm_resMessageChecksSaved, [IntToStr(SL.Count)]), mtInformation, [mbOk], Self)
      end;
  finally
    SL.Free;
  end;
end;

procedure TMainFrm.miLoadClick(Sender: TObject);
var
  SL: TStringList;
  I: Integer;
  Node: PVirtualNode;
  Data: PData;
  CheckCount: Integer;
begin
  if OD.Execute then
  begin
    CheckCount := 0;
    SL := TStringList.Create;
    try
      SL.LoadFromFile(OD.FileName);
      for I := 0 to SL.Count - 1 do
      begin
        Node := VisualTree.VST.GetFirst;
        while Node <> nil do
        begin
          Data := VisualTree.VST.GetNodeData(Node);
          if UpperCase(Trim(Data^.LazarusPackageName)) = UpperCase(Trim(SL.Strings[I])) then
          begin
            VisualTree.VST.CheckState[Node] := csCheckedNormal;
            Inc(CheckCount);
            Break;
          end;
          Node := VisualTree.VST.GetNext(Node);
        end;
      end;
    finally
      SL.Free;
    end;
    if CheckCount > 0 then
       MessageDlgEx(Format(rsMainFrm_resMessageChecksLoaded, [IntToStr(CheckCount)]), mtInformation, [mbOk], Self)
  end;
end;


procedure TMainFrm.pnMainResize(Sender: TObject);
begin
  pnMessage.Left := (pnMain.Width - pnMessage.Width) div 2;
  pnMessage.Top := (pnMain.Height - pnMessage.Height) div 2;
end;

procedure TMainFrm.miJSONShowClick(Sender: TObject);
begin
  if not mJSON.Visible then
  begin
    StopUpdates;
    EnableDisableControls(False);
    mJSON.Visible := True;
    mJSON.BringToFront;
  end
  else
  begin
    mJSON.SendToBack;
    mJSON.Visible := False;
    EnableDisableControls(True);
    StartUpdates;
  end;
end;

procedure TMainFrm.miNameAscClick(Sender: TObject);
var
  JSON: TJSONStringType;
begin
  JSON := '';
  case (Sender as TMenuItem).Tag of
    0: SerializablePackages.Sort(stName, soAscendent);
    1: SerializablePackages.Sort(stName, soDescendent);
    2: SerializablePackages.Sort(stDate, soAscendent);
    3: SerializablePackages.Sort(stDate, soDescendent);
  end;
  SerializablePackages.PackagesToJSON(JSON);
  mJSON.Lines.BeginUpdate;
  try
    mJSON.Clear;
    mJSON.Text := JSON;
  finally
    mJSON.Lines.EndUpdate;
  end;
end;

procedure TMainFrm.miSaveToFileClick(Sender: TObject);
var
  JSON: TJSONStringType;
  Ms: TMemoryStream;
begin
  SD.DefaultExt := '.*.json';
  SD.Filter := '*.json|*.json';
  if SD.Execute then
  begin
    JSON := '';
    SerializablePackages.PackagesToJSON(JSON);
    Ms := TMemoryStream.Create;
    try
      Ms.Write(Pointer(JSON)^, Length(JSON));
      Ms.Position := 0;
      Ms.SaveToFile(SD.FileName);
    finally
      Ms.Free;
    end;
  end;
end;

procedure TMainFrm.SetupControls;
var
  I: Integer;
begin
  Caption := rsLazarusPackageManager;

  cbFilterBy.Clear;
  cbFilterBy.Items.Add(rsMainFrm_VSTHeaderColumn_PackageName);
  cbFilterBy.Items.Add(rsMainFrm_VSTHeaderColumn_LazarusPackage);
  cbFilterBy.Items.Add(rsMainFrm_VSTText_PackageCategory);
  cbFilterBy.Items.Add(rsMainFrm_VSTText_PackageStatus);
  cbFilterBy.Items.Add(rsMainFrm_VSTText_Version);
  cbFilterBy.Items.Add(rsMainFrm_VSTText_Description);
  cbFilterBy.Items.Add(rsMainFrm_VSTText_Author);
  cbFilterBy.Items.Add(rsMainFrm_VSTText_LazCompatibility);
  cbFilterBy.Items.Add(rsMainFrm_VSTText_FPCCompatibility);
  cbFilterBy.Items.Add(rsMainFrm_VSTText_SupportedWidgetsets);
  cbFilterBy.Items.Add(rsMainFrm_VSTText_Packagetype);
  cbFilterBy.Items.Add(rsMainFrm_VSTText_Dependecies);
  cbFilterBy.Items.Add(rsMainFrm_VSTText_License);
  cbFilterBy.ItemIndex := 0;

  cbPackageType.Clear;
  cbPackageType.Items.Add('');
  cbPackageType.Items.Add(rsMainFrm_VSTText_PackageType2);
  cbPackageType.Items.Add(rsMainFrm_VSTText_PackageType1);
  cbPackageType.Items.Add(rsMainFrm_VSTText_PackageType0);
  cbPackageType.Items.Add(rsMainFrm_VSTText_PackageType3);

  cbPackageState.Clear;
  cbPackageState.Items.Add('');
  cbPackageState.Items.Add(rsMainFrm_VSTText_PackageState0);
  cbPackageState.Items.Add(rsMainFrm_VSTText_PackageState1);
  cbPackageState.Items.Add(rsMainFrm_VSTText_PackageState2);
  cbPackageState.Items.Add(rsMainFrm_VSTText_PackageState3);

  cbPackageCategory.Clear;
  cbPackageCategory.Items.Add('');
  for I := 0 to MaxCategories - 1 do
  cbPackageCategory.Items.Add(Categories[I]);

  tbRefresh.Caption := rsMainFrm_TBRefresh_Caption;
  tbRefresh.Hint := rsMainFrm_TBRefresh_Hint;
  tbDownload.Caption := rsMainFrm_TBDownload_Caption;
  tbDownload.Hint := rsMainFrm_TBDownload_Hint;
  tbInstall.Caption := rsMainFrm_TBInstall_Caption;
  tbInstall.Hint := rsMainFrm_TBInstall_Hint;
  tbUpdate.Caption := rsMainFrm_TBUpdate_Caption;
  tbUpdate.Hint := rsMainFrm_TBUpdate_Hint;
  tbUninstall.Caption := rsMainFrm_TBUninstall_Caption;
  tbUninstall.Hint := rsMainFrm_TBUninstall_Hint;
  tbOpenRepo.Caption := rsMainFrm_TBOpenRepo_Caption;
  tbOpenRepo.Hint := rsMainFrm_TBOpenRepo_Hint;
  tbCleanUp.Caption := rsMainFrm_TBCleanUp_Caption;
  tbCleanUp.Hint := rsMainFrm_TBCleanUp_Hint;
  tbCreate.Caption := rsMainFrm_TBRepository_Caption;
  tbCreate.Hint := rsMainFrm_TBRepository_Hint;
  tbOptions.Caption := rsMainFrm_TBOptions_Caption;
  tbOptions.Hint := rsMainFrm_TBOptions_Hint;
  tbHelp.Caption := rsMainFrm_TBHelp_Caption;
  tbHelp.Hint := rsMainFrm_TBHelp_Hint;

  miFromRepository.Caption := rsMainFrm_miFromRepository;
  miFromExteranlSource.Caption := rsMainFrm_miFromExternalSource;
  miCreateRepositoryPackage.Caption := rsMainFrm_miCreateRepositoryPackage;
  miCreateJSONForUpdates.Caption := rsMainFrm_miCreateJSONForUpdates;
  miCreateRepository.Caption := rsMainFrm_miCreateRepository;
  miJSONShow.Caption := rsMainFrm_miJSONShow;
  miJSONHide.Caption := rsMainFrm_miJSONHide;
  miJSONSort.Caption := rsMainFrm_miJSONSort;
  miByName.Caption := rsMainFrm_miByName;
  miNameAsc.Caption := rsMainFrm_miAscendent;
  miNameDsc.Caption := rsMainFrm_miDescendent;
  miByDate.Caption := rsMainFrm_miByDate;
  miDateAsc.Caption := rsMainFrm_miAscendent;
  miDateDsc.Caption := rsMainFrm_miDescendent;
  miSaveToFile.Caption := rsMainFrm_miSaveToFile;
  miCopyToClpBrd.Caption := rsMainFrm_miCopyToClpBrd;
  miResetRating.Caption := rsMainFrm_miResetRating;
  miSave.Caption := rsMainFrm_miSave;
  miSaveChecked.Caption := rsMainFrm_miSaveChecked;
  miSaveInstalled.Caption := rsMainFrm_miLoadInstalled;
  miLoad.Caption := rsMainFrm_miLoad;
  edFilter.Hint := rsMainFrm_edFilter_Hint;
  spClear.Hint := rsMainFrm_spClear_Hint;
  cbFilterBy.Top := (pnTop.Height - cbFilterBy.Height) div 2;
  pnFilter.Height := cbFilterBy.Height;
  pnFilter.Top := (pnTop.Height - pnFilter.Height) div 2;
  cbPackageState.Top := (pnTop.Height - cbPackageState.Height) div 2;
  cbPackageType.Top := (pnTop.Height - cbPackageType.Height) div 2;
  cbPackageCategory.Top := (pnTop.Height - cbPackageCategory.Height) div 2;
  cbAll.Top := (pnTop.Height - cbAll.Height) div 2;
  cbAll.Hint := rsMainFrm_cbAll_Hint;
  spExpand.Top:= (pnTop.Height - spExpand.Height + 1) div 2;
  spExpand.Hint := rsMainFrm_spExpand_Hint;
  spCollapse.Top:= (pnTop.Height - spCollapse.Height + 1) div 2;
  spCollapse.Hint := rsMainFrm_spCollapse_Hint;
  cbAll.Caption := rsMainFrm_cbAll_Caption;
  lbFilterBy.Top := cbFilterBy.Top + (cbFilterBy.Height - lbFilterBy.Height) div 2;
  lbFilterBy.Caption := rsMainFrm_lbFilter_Caption;
  cbFilterBy.Hint := rsMainFrm_cbFilterBy_Hint;

  cbPackageCategory.Visible := False;
  cbPackageType.Visible := False;
  cbPackageState.Visible := False;
end;

procedure TMainFrm.SetupColors;
begin
  VisualTree.SetupColors;
  if not Options.UseDefaultTheme then
  begin
    Self.Color := clBtnFace;
    pnMain.Color := clBtnFace;
    pnMessage.Color := clBtnFace;
    pnTop.Color := clBtnFace;
    mJSON.Color := clBtnFace;
  end
  else
  begin
    pnMain.Color := VisualTree.VST.GetDefaultColor(dctBrush);
    pnMessage.Color := VisualTree.VST.GetDefaultColor(dctBrush);
  end;
end;

end.

















