require 'test/unit'
require 'phi'

module Phi
  class ListItem
    def inspect
      "#<#{self.class}:#{'0x%x'%self.object_id} caption=#{self.caption.inspect}>"
    end
  end
end

class TCListView < Test::Unit::TestCase
  def test_font
    form = Phi::Form.new
    instance = Phi::ListView.new(form, :list_view)
    assert_instance_of Phi::Font, instance.font
  end

=begin

FindCaption メソッドは，指定されたキャプションのリストビュー項目がある場合にそれを返します。

function FindCaption(StartIndex: Integer; Value: string; Partial, Inclusive, Wrap: Boolean): TListItem;

説明

FindCaption メソッドを呼び出すと，Value パラメータで指定した文字列でラベル付けされたリストビュー項目を検索できます。

Inclusive パラメータが True の場合，StartIndex で指定したリスト項目から検索が始まります。
それ以外の場合，検索は次の項目から開始されます。

Wrap パラメータが True の場合，一致する項目が見つからなければ先頭に戻って検索が続行されます。
FindCaption は，Value に等しい Caption プロパティを持つ最初の項目を返します。

Partial パラメータが True の場合，Caption が部分文字列 Value で始まっていれば検出されます。
Partial パラメータが False の場合，Caption は Value と正確に一致しなければなりません。

一致する項目が見つからない場合，FindCaption は nil を返します。

=end
  def test_find_caption
    form = Phi::Form.new
    lv = Phi::ListView.new(form)
    
    # lv.find_caption(nil)
    #=> ArgumentError: wrong number of arguments (1 for 5)
    
    # lv.find_caption(0,nil,false,false,false)
    #=> TypeError: wrong argument type nil (expected String)
    
    assert_nil(lv.find_caption(0,'',false,false,false))
    
    # アイテムを1個追加
    item = lv.items.add
    item.caption = "abc"
    
    assert_nil(lv.find_caption(0,'',false,false,false))
    
    # inclusive パラメータのテスト
    assert_equal(item, lv.find_caption(-1,'abc',false,false,false))
    assert_equal(item, lv.find_caption(0,'abc',false,true,false))
    assert_nil(lv.find_caption(0,'abc',false,false,false))
    
    # inclusive, partial パラメータのテスト
    assert_nil(lv.find_caption(-1,'ab',false,false,false))
    assert_nil(lv.find_caption(0,'ab',false,true,false))
    
    assert_equal(item, lv.find_caption(-1,'ab',true,false,false))
    assert_equal(item, lv.find_caption(0,'ab',true,true,false))
    assert_nil(lv.find_caption(0,'ab',true,false,false))
    
    # キャプションを空文字列にする
    item.caption = ""
    
    # inclusive パラメータのテスト
    assert_equal(item, lv.find_caption(-1,'',false,false,false))
    assert_equal(item, lv.find_caption(0,'',false,true,false))
    assert_nil(lv.find_caption(0,'',false,false,false))
    
    # アイテムをもう1個追加(後ろに)
    item2 = lv.items.add
    item2.caption = "abc"
    
    # inclusive パラメータのテスト
    assert_equal(item2, lv.find_caption(0,'abc',false,false,false))
    assert_equal(item2, lv.find_caption(1,'abc',false,true,false))
    assert_nil(lv.find_caption(1,'abc',false,false,false))
    
    # inclusive, partial パラメータのテスト
    assert_nil(lv.find_caption(0,'ab',false,false,false))
    assert_nil(lv.find_caption(1,'ab',false,true,false))
    
    assert_equal(item2, lv.find_caption(0,'ab',true,false,false))
    assert_equal(item2, lv.find_caption(1,'ab',true,true,false))
    assert_nil(lv.find_caption(1,'ab',true,false,false))
    
    # start_index パラメータのテスト
    assert_equal(item, lv.find_caption(-1,'',false,false,false))
    assert_equal(item, lv.find_caption(0,'',false,true,false))
    assert_nil(lv.find_caption(0,'',false,false,false))
    
    # start_index, wrap パラメータのテスト
    assert_nil(lv.find_caption(0,'',false,false,false))
    assert_nil(lv.find_caption(1,'',false,true,false))
    assert_nil(lv.find_caption(1,'',false,false,false))
    
    assert_equal(item, lv.find_caption(0,'',false,false,true))
    assert_equal(item, lv.find_caption(1,'',false,true,true))
    assert_equal(item, lv.find_caption(1,'',false,false,true))
    
  end

=begin

FindData

Apolloでは TListItem.Data には対応するRubyオブジェクトの Tvalue 値を格納する。
ListItem#data は TListItem.Data とは結びついていない。
なので、ListView#find_data を TListView.FindData を基に実装しても元の意味では使えない。

=end

=begin

OwnerData

TListView.OwnerData := True によって動作が変化するメソッドを確認してみる。

$(Delphi6)\Source\Vcl\ComCtrls.pas:

function TListItem.GetChecked: Boolean;
begin
  with Owner.Owner do
    if not OwnerData and HandleAllocated then
      Result := (ListView_GetCheckState(Handle, Index) <> 0)
    else
      Result := FChecked;
end;

これによれば Checked プロパティは OwnerData = True のときは FChecked の値を返す。

procedure TListItem.SetChecked(Value: Boolean);
var
  LV: TCustomListView;
begin
  if Value <> Checked then
  begin
    FChecked := Value;
    LV := Owner.Owner;
    if not LV.OwnerData and LV.HandleAllocated then
      ListView_SetCheckState(LV.Handle, Index, Value);
  end;
end;

設定するほうは OwnerData に関わらず常に FCheck を設定する。
OwnerData = True のとき TListItem は sengleton になるから、
OwnerData = True のとき TListItem.Checked はアイテムの違いによらず常に同じ値を返すはずである。

----
Checked プロパティは，リスト項目の隣にチェックマークが表示されるかどうかを指定します。

property Checked: Boolean;

説明

Checked プロパティは，リスト項目が，選択されているオプションをリストビューでリスト項目の隣にチェックマークを付けて表示するかどうかを指定できます。Checked が True ならば，項目の隣にチェックマークが表示されます。Checked が False ならば，チェックマークは表示されません。

注意  Checked プロパティを使用する前に，ListView の CheckBoxes プロパティを True に設定してください。
----

=end

  def test_owner_data
    form = Phi::Form.new
    lv = Phi::ListView.new(form)
# lv.owner_draw = true
    assert_equal(false, lv.owner_data)
    lv.owner_data = true
    assert_equal(true, lv.owner_data)
    
    # Delphi6 ヘルプでは見出しが CheckBoxes になっているが Checkboxes の誤りである。
    assert_equal(false, lv.checkboxes)
    lv.checkboxes = true
    assert_equal(true, lv.checkboxes)
    
    item = lv.items.add
    item.caption = "abc"
    
#  この位置で owner_draw を変えると items 的にまずいらしい (false->true or true->false)
#  lv.owner_draw = true
#  # or lv.owner_draw = false (事前に lv.owner_draw = true としたとき)
#  p item
#  #<Phi::ListItem:0x876ff4 caption="">
#  p item.checked
#  C:/usr/lib/ruby/1.8/test/unit/autorunner.rb:20: in `checked': モジュール 'vcl60.bpl' のアドレス 4013D1FB でアドレス 00000084 に対する読み込み違反がおきました。(EAccessViolation)
    
    assert_equal(false, item.checked)
    item.checked = true
    assert_equal(true, item.checked)
    
    item2 = lv.items.add
    item2.caption = "def"
    
    assert_equal(false, item2.checked)
    item2.checked = true
    assert_equal(true, item2.checked)
    assert_equal(true, item.checked)
    
    # TListItems.Add で生成した TListItem は OwnerData = True であっても新規のオブジェクトである。
    # TListItems.AddItem は Item パラメータが nil のとき Owner.CreateListItem を呼ぶ。
    item2.checked = false
    assert_equal(false, item2.checked)
    assert_equal(true, item.checked)
    
    # OwnerData = True のときこれらは一致しない。
    # ListItems#[] は常に同じオブジェクトを返す。
    assert_not_equal(item, lv.items[0])
    assert_not_equal(item2, lv.items[1])
    
    # ListItems.GetItem で OwnerData = True のとき mask = 0 なので (irText がないので)
    # Caption は '' になる。
    assert_equal("", lv.items[0].caption)
    assert_equal("", lv.items[1].caption)
    
    tmp_item = lv.items[0]
    tmp_item.caption = "foo"
    assert_equal("foo", tmp_item.caption)
    
    assert_equal(false, tmp_item.checked)
    tmp_item.checked = true
    assert_equal(true, tmp_item.checked)
    
    # ListItems_aref で @tmp_item に格納しない場合:
    # assert_equal("", lv.items[0].caption)
    # assert_equal("", lv.items[1].caption)
    # 直前の ListItems#[] すなわち ListItems.GetItem により上書きされる。
    # assert_equal("", tmp_item.caption)
    
    assert_equal("foo", lv.items[0].caption)
    assert_equal("foo", lv.items[1].caption)
    assert_equal("foo", tmp_item.caption)
    assert_equal(tmp_item, lv.items[0])
    assert_equal(tmp_item, lv.items[1])
    
    assert_equal(true, lv.items[0].checked)
    assert_equal(true, lv.items[1].checked)
    assert_equal(true, tmp_item.checked)
  end

end
