view src/myframe.cpp @ 27:d21de4693652 v2.2dev v2.3

add hhsname
author pyon@macmini
date Sat, 05 Nov 2011 10:13:41 +0900
parents 5a934c8e1b95
children 24283d3a9592
line wrap: on
line source

// Filename   : myframe.cpp
// Last Change: 05-Nov-2011.
//

#include "main.h"
#include "myframe.h"
#include "param.h"
#include "dndfile.h"
#include "marksheet.h"

#define LOGO_W  288
#define LOGO_H   86
#define HHSN_W  288
#define HHSN_H   49
#define THUMB_W 160
#define THUMB_H 226

// resources
// the application icon (under Windows and OS/2 it is in resources and even
// though we could still include the XPM here it would be unused)
#if !defined(__WXMSW__) && !defined(__WXPM__)
    #include "sample.xpm"
#endif

//////////////////////////////////////////////////////////////////////////
// frame constructor
MyFrame::MyFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
{
    this->SetBackgroundColour( wxColour(wxT("WHEAT")) );
    // set the frame icon
    SetIcon(wxICON(sample));
	
    // メニューバー
	m_menubarFile = new wxMenuBar();
	m_menuFile = new wxMenu();
	wxMenuItem* m_menuItemParam;
	m_menuItemParam = new wxMenuItem( m_menuFile, ID_MENUITEMPARAM, wxString( wxT("パラメータ(&P)") ) , wxEmptyString, wxITEM_NORMAL );
	m_menuFile->Append( m_menuItemParam );
	
	wxMenuItem* m_menuItemAppDIr;
	m_menuItemAppDIr = new wxMenuItem( m_menuFile, ID_MENUITEMAPPDIR, wxString( wxT("アプリフォルダを開く(&O)") ) , wxEmptyString, wxITEM_NORMAL );
	m_menuFile->Append( m_menuItemAppDIr );
	
	wxMenuItem* m_separator;
	m_separator = m_menuFile->AppendSeparator();    // ----
	
	wxMenuItem* m_menuItemQuit;
	m_menuItemQuit = new wxMenuItem( m_menuFile, ID_MENUITEMQUIT, wxString( wxT("終了(&X)") ) , wxEmptyString, wxITEM_NORMAL );
	m_menuFile->Append( m_menuItemQuit );
	
	m_menubarFile->Append( m_menuFile, wxT("ファイル(&F)") ); 
	
	this->SetMenuBar( m_menubarFile );
	
    // コントロール	
	wxBoxSizer* bSizerTop = new wxBoxSizer( wxVERTICAL );
	
	wxBoxSizer* bSizerFrom = new wxBoxSizer( wxHORIZONTAL );
	
	m_staticTextWork = new wxStaticText( this, wxID_ANY, wxT("作業フォルダ"), wxDefaultPosition, wxDefaultSize, 0 );
	bSizerFrom->Add( m_staticTextWork, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
	
	m_dirPickerWork = new wxDirPickerCtrl( this, wxID_ANY, wxGetApp().workdir, wxT("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_DEFAULT_STYLE );
	bSizerFrom->Add( m_dirPickerWork, 1, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
	
	bSizerTop->Add( bSizerFrom, 0, wxEXPAND, 5 );
	
	wxBoxSizer* bSizerDist = new wxBoxSizer( wxHORIZONTAL );
	
	m_staticTextDist = new wxStaticText( this, wxID_ANY, wxT("保存フォルダ"), wxDefaultPosition, wxDefaultSize, 0 );
	bSizerDist->Add( m_staticTextDist, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
	
	m_textCtrlDist = new wxTextCtrl( this, ID_TEXTCTRLDIST, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
	m_textCtrlDist->SetMaxLength( 15 ); 
	bSizerDist->Add( m_textCtrlDist, 1, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
	bSizerDist->Add( 0, 0, 1, wxEXPAND, 5 );
	
	m_staticTextDrive = new wxStaticText( this, wxID_ANY, wxT("ドライブ"), wxDefaultPosition, wxDefaultSize, 0 );
	bSizerDist->Add( m_staticTextDrive, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
	
    wxArrayString drives;
    drives.Add(wxT("C:"));
    drives.Add(wxT("Y:"));
    drives.Add(wxT("Z:"));
	m_comboBoxDrive = new wxComboBox( this, wxID_ANY, wxT("C:"), wxDefaultPosition, wxSize(50,-1), drives, 0 ); 
	bSizerDist->Add( m_comboBoxDrive, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
	
	m_staticTextDate = new wxStaticText( this, wxID_ANY, wxT("開催日"), wxDefaultPosition, wxDefaultSize, 0 );
	bSizerDist->Add( m_staticTextDate, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
	
	m_datePicker = new wxDatePickerCtrl( this, wxID_ANY, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, wxDP_DROPDOWN );
	bSizerDist->Add( m_datePicker, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );

	m_buttonNextThu = new wxButton( this, ID_BUTTONNEXTTHU, wxT("次木 >>"), wxDefaultPosition, wxSize(60,-1), 0 );
	bSizerDist->Add( m_buttonNextThu, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
	
	m_staticTextCcn = new wxStaticText( this, wxID_ANY, wxT("合議体"), wxDefaultPosition, wxDefaultSize, 0 );
	bSizerDist->Add( m_staticTextCcn, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
	
    wxArrayString ccns;
	ccns.Add(wxT("角館1")); ccns.Add(wxT("角館2")); ccns.Add(wxT("角館3")); ccns.Add(wxT("角館4"));
	ccns.Add(wxT("西仙1")); ccns.Add(wxT("西仙2")); ccns.Add(wxT("西仙3"));
	ccns.Add(wxT("千畑1")); ccns.Add(wxT("千畑2")); ccns.Add(wxT("千畑3"));
	ccns.Add(wxT("大曲1")); ccns.Add(wxT("大曲2")); ccns.Add(wxT("大曲3")); ccns.Add(wxT("大曲4")); ccns.Add(wxT("大曲5")); ccns.Add(wxT("大曲6"));
	ccns.Add(wxT("六郷1")); ccns.Add(wxT("六郷2")); ccns.Add(wxT("六郷3"));
	m_comboBoxCcn = new wxComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(100,-1), ccns, 0 ); 
	bSizerDist->Add( m_comboBoxCcn, 0, wxALL, 5 );
	
	m_buttonMkDir = new wxButton( this, ID_BUTTONMKDIR, wxT("適用"), wxDefaultPosition, wxDefaultSize, 0 );
	bSizerDist->Add( m_buttonMkDir, 0, wxALL, 5 );
	
	bSizerTop->Add( bSizerDist, 0, wxEXPAND, 5 );
	
	wxBoxSizer* bSizerManip = new wxBoxSizer( wxHORIZONTAL );
	
	wxBoxSizer* bSizerRecog = new wxBoxSizer( wxVERTICAL );
	
	m_staticTextName = new wxStaticText( this, wxID_ANY, wxT("氏名"), wxDefaultPosition, wxDefaultSize, 0 );
	bSizerRecog->Add( m_staticTextName, 0, wxTOP|wxLEFT, 5 );
    wxString logo = wxGetCwd() + wxFILE_SEP_PATH + wxT("image") + wxFILE_SEP_PATH + wxT("logo.png");
    wxBitmap bmp = wxBitmap( logo, wxBITMAP_TYPE_PNG );
	m_bitmapName = new wxStaticBitmap( this, wxID_ANY, bmp, wxDefaultPosition, wxSize(320,95), 0 );
	bSizerRecog->Add( m_bitmapName, 0, wxTOP|wxBOTTOM|wxLEFT, 5 );
	
	m_staticTextHhsno = new wxStaticText( this, wxID_ANY, wxT("被保険者番号"), wxDefaultPosition, wxDefaultSize, 0 );
	bSizerRecog->Add( m_staticTextHhsno, 0, wxTOP|wxLEFT, 5 );
    logo = wxGetCwd() + wxFILE_SEP_PATH + wxT("image") + wxFILE_SEP_PATH + wxT("0123456789.png");
    bmp.LoadFile( logo, wxBITMAP_TYPE_PNG );
	m_bitmapHhsno = new wxStaticBitmap( this, wxID_ANY, bmp, wxDefaultPosition, wxSize(320,54), 0 );
	bSizerRecog->Add( m_bitmapHhsno, 0, wxTOP|wxBOTTOM|wxLEFT, 5 );
	
	m_staticTextGuess = new wxStaticText( this, wxID_ANY, wxT("推定値"), wxDefaultPosition, wxDefaultSize, 0 );
	bSizerRecog->Add( m_staticTextGuess, 0, wxTOP|wxLEFT, 5 );

	wxBoxSizer* bSizerGuess = new wxBoxSizer( wxHORIZONTAL );

	m_textCtrlGuess = new wxTextCtrl( this, ID_TEXTCTRLGUESS, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
	m_textCtrlGuess->SetMaxLength( 10 ); 
	bSizerGuess->Add( m_textCtrlGuess, 0, wxALL, 5 );

	m_textCtrlName = new wxTextCtrl( this, ID_TEXTCTRLNAME, wxEmptyString, wxDefaultPosition, wxSize(140,-1), 0 );
    m_textCtrlName->SetBackgroundColour(wxT("LIGHT GREY"));
	bSizerGuess->Add( m_textCtrlName, 0, wxALL, 5 );
	
	bSizerRecog->Add( bSizerGuess, 0, wxEXPAND, 5 );

	bSizerManip->Add( bSizerRecog, 0, wxEXPAND|wxLEFT, 5 );
	
	m_listCtrlView = new wxListCtrl( this, ID_LISTCTRLVIEW, wxDefaultPosition, wxDefaultSize, wxLC_ICON );
    m_listCtrlView->SetBackgroundColour(wxT("LIGHT GREY"));
	bSizerManip->Add( m_listCtrlView, 1, wxTOP|wxRIGHT|wxBOTTOM|wxEXPAND, 5 );
    m_imageList = new wxImageList( THUMB_W, THUMB_H );
    m_listCtrlView->AssignImageList( m_imageList, wxIMAGE_LIST_NORMAL );
    //m_listCtrlView->SetDropTarget( new DnDFile(m_dirPickerWork) );
    this->SetDropTarget( new DnDFile(m_dirPickerWork) );
	
	wxBoxSizer* bSizerButton = new wxBoxSizer( wxVERTICAL );
	wxGridSizer* gSizer = new wxGridSizer( 2, 2, 0, 0 );
	
	m_buttonMove = new wxButton( this, ID_BUTTONMOVE, wxT("移動"), wxDefaultPosition, wxDefaultSize, 0 );
	gSizer->Add( m_buttonMove, 0, wxALL, 5 );
    m_buttonMove->Enable(false);
	m_buttonDetect = new wxButton( this, ID_BUTTONDETECT, wxT("検知"), wxDefaultPosition, wxDefaultSize, 0 );
	gSizer->Add( m_buttonDetect, 0, wxALL, 5 );

	m_buttonDel = new wxButton( this, ID_BUTTONDEL, wxT("削除"), wxDefaultPosition, wxDefaultSize, 0 );
	gSizer->Add( m_buttonDel, 0, wxALL, 5 );
	m_buttonUndo = new wxButton( this, ID_BUTTONUNDO, wxT("戻す"), wxDefaultPosition, wxDefaultSize, 0 );
	gSizer->Add( m_buttonUndo, 0, wxALL, 5 );
    m_buttonUndo->Enable(false);

	bSizerButton->Add( gSizer, 0, wxALL, 5 );

	m_listCtrlHhsDir = new wxListCtrl( this, ID_LISTCTRLDIR, wxDefaultPosition, wxSize(280,-1), wxLC_REPORT|wxLC_SINGLE_SEL );
    wxListItem itemCol;
    itemCol.SetText( wxT("通番") );
    m_listCtrlHhsDir->InsertColumn( 0, itemCol );
    m_listCtrlHhsDir->SetColumnWidth( 0, 40 );
    itemCol.SetText( wxT("被保険者番号") );
    m_listCtrlHhsDir->InsertColumn( 1, itemCol );
    m_listCtrlHhsDir->SetColumnWidth( 1, 90 );
    itemCol.SetText( wxT("枚数") );
    m_listCtrlHhsDir->InsertColumn( 2, itemCol );
    m_listCtrlHhsDir->SetColumnWidth( 2, 40 );
    itemCol.SetText( wxT("氏名") );
    m_listCtrlHhsDir->InsertColumn( 3, itemCol );
    m_listCtrlHhsDir->SetColumnWidth( 3, 90 );

	bSizerButton->Add( m_listCtrlHhsDir, 1, wxEXPAND|wxALL, 5 );
	
	bSizerManip->Add( bSizerButton, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
	
	bSizerTop->Add( bSizerManip, 1, wxEXPAND, 5 );
	
	this->SetSizer( bSizerTop );
	this->Layout();

    // ステータスバー
    int widths[] = { 250, 250, -1, 120 };
    m_statusBar = this->CreateStatusBar( WXSIZEOF(widths), wxST_SIZEGRIP );
    m_statusBar->SetStatusWidths( WXSIZEOF(widths), widths );
    m_statusBar->SetStatusText( wxEmptyString, 0 );
	
	this->Centre( wxBOTH );
    m_timer.SetOwner( this, ID_TIMER );
}

// destructor
MyFrame::~MyFrame()
{
}

// Event Table
BEGIN_EVENT_TABLE( MyFrame, wxFrame )
    EVT_CHAR( MyFrame::OnChar )
    EVT_IDLE( MyFrame::OnIdle )
    EVT_TIMER( ID_TIMER, MyFrame::OnTimer )
    EVT_SIZE( MyFrame::OnWinSize )
    EVT_MOVE( MyFrame::OnWinMove )
    EVT_MENU( ID_MENUITEMPARAM,   MyFrame::OnParam )
    EVT_MENU( ID_MENUITEMAPPDIR,  MyFrame::OnOpenAppDir )
    EVT_MENU( wxID_EXIT,          MyFrame::OnQuit )
    EVT_LIST_ITEM_SELECTED(   ID_LISTCTRLVIEW, MyFrame::OnItemSelected )
    EVT_LIST_ITEM_DESELECTED( ID_LISTCTRLVIEW, MyFrame::OnItemDeselected )
    EVT_LIST_ITEM_ACTIVATED(  ID_LISTCTRLVIEW, MyFrame::ViewLarge )
    EVT_BUTTON( ID_BUTTONNEXTTHU, MyFrame::OnNextThursday )
    EVT_BUTTON( ID_BUTTONMKDIR,   MyFrame::OnMakeDir )
    EVT_BUTTON( ID_BUTTONDETECT,  MyFrame::OnDetect )
    EVT_BUTTON( ID_BUTTONMOVE,    MyFrame::OnMove )
    EVT_BUTTON( ID_BUTTONDEL,     MyFrame::OnDelete )
    EVT_BUTTON( ID_BUTTONUNDO,    MyFrame::OnUndo )
    EVT_LIST_ITEM_ACTIVATED( ID_LISTCTRLDIR, MyFrame::OnOpenHhsDir )
    EVT_CLOSE( MyFrame::SaveConfig )
END_EVENT_TABLE()

// Event Handlers
/* 次の木曜日 */
void MyFrame::OnNextThursday(wxCommandEvent& WXUNUSED(event))
{
	wxDateTime dt = m_datePicker->GetValue();
    wxDateSpan ds( 0, 0, 0, 1 );
    dt += ds;
    dt.SetToNextWeekDay( wxDateTime::Thu );
    m_datePicker->SetValue( dt );
}

/* 移動先フォルダ作成 */
void MyFrame::OnMakeDir(wxCommandEvent& WXUNUSED(event))
{
    wxString to;
    to.Append( m_comboBoxDrive->GetValue() );
    to.Append( wxFILE_SEP_PATH );
    wxDateTime dt = m_datePicker->GetValue();
    to.Append( dt.Format(wxT("%Y%m%d")) );
    to.Append( wxFILE_SEP_PATH );
    to.Append( m_comboBoxCcn->GetValue() );
    m_textCtrlDist->SetValue( to );

    wxString ccn = m_comboBoxCcn->GetValue();
    if ( to.Len() < 15 || ccn.IsEmpty() ) {
        wxMessageBox(wxT("フォルダを指定してください."));
        return;
    }

    wxStringTokenizer tkz( to, wxFILE_SEP_PATH );
    wxString d;
    while ( tkz.HasMoreTokens() ) {
        d.Append( tkz.GetNextToken() );
        d.Append( wxFILE_SEP_PATH );
        if ( !wxDirExists( d ) ) wxMkdir( d );
    }
    m_buttonMove->Enable(true);

    // TODO.
    // make 申請書ふぉるだ

    wxMessageBox(wxT("移動先フォルダ準備完了"));
    wxString cmd = wxT("explorer ") + to;
    wxExecute( cmd );
}
/* 検知 */
void MyFrame::OnDetect(wxCommandEvent& WXUNUSED(event))
{
    F5_Shortcut(); // UpdateCache -> UpdateListImage
}

/* 移動 */
void MyFrame::OnMove(wxCommandEvent& WXUNUSED(event))
{
    F7_Shortcut(); // MoveImages -> UpdateCache -> UpdateListImage -> ListHhsDir
}

/* 選択したファイルを移動 */
void MyFrame::MoveImages()
{
    m_undo.Clear();
    wxString workdir = m_dirPickerWork->GetPath();
    wxString distdir = m_textCtrlDist->GetValue();
    wxString hhsno = m_textCtrlGuess->GetValue();

    m_hhsList.Remove(hhsno);
    m_hhsList.Add(hhsno);
    long item = -1;
    for ( ;; ) {
        item = m_listCtrlView->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
        if ( item == -1 ) break;
        if ( !wxDirExists( distdir + wxFILE_SEP_PATH + hhsno ) ) wxMkdir( distdir + wxFILE_SEP_PATH + hhsno );

        wxString file  = m_listCtrlView->GetItemText( item );
        wxString from = workdir + wxFILE_SEP_PATH + file;
        wxString to   = distdir + wxFILE_SEP_PATH + hhsno + wxFILE_SEP_PATH + file;
        wxRenameFile( from, to, true );

        wxString movecmd = MOVECMD;
        m_undo.Insert( movecmd + wxT(" ") + to + wxT(" ") + from, 0 );
    }
}
/* 選択したファイルを削除 */
void MyFrame::OnDelete(wxCommandEvent& WXUNUSED(event))
{
    m_undo.Clear();
    wxString workdir = m_dirPickerWork->GetPath();
    wxString trash   = wxGetCwd() + wxFILE_SEP_PATH + wxT("trash");
    long item = -1;
    for ( ;; ) {
        item = m_listCtrlView->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
        if ( item == -1 ) break;
        wxString file = m_listCtrlView->GetItemText( item );
        wxString from = workdir + wxFILE_SEP_PATH + file;
        wxString to   = trash   + wxFILE_SEP_PATH + file;
        wxRenameFile( from, to, true );

        wxString movecmd = MOVECMD;
        m_undo.Insert( movecmd + wxT(" ") + to + wxT(" ") + from, 0 );
    }
    UpdateCache();
    UpdateListImage();
    m_buttonUndo->Enable(true);
}
/* アンドゥ */
void MyFrame::OnUndo(wxCommandEvent& WXUNUSED(event))
{
    for ( int i=0; i<m_undo.GetCount(); i++ ) {
        wxExecute( m_undo[i] );
    }
    wxMessageBox(wxT("戻し完了."));
    m_buttonUndo->Enable(false);
    m_undo.Clear();
    UpdateCache();
    UpdateListImage();
    ListHhsDir();
}

/* 画像をリストコントロールに表示 */
void MyFrame::UpdateListImage()
{
    // start-up iamge
    wxString notfound = wxGetCwd() + wxFILE_SEP_PATH + wxT("image") + wxFILE_SEP_PATH + wxT("notfound.png");
    wxBitmap bmp = wxBitmap( notfound, wxBITMAP_TYPE_PNG );
    m_bitmapName->SetBitmap( bmp );
    notfound = wxGetCwd() + wxFILE_SEP_PATH + wxT("image") + wxFILE_SEP_PATH + wxT("0000000000.png");
    bmp.LoadFile( notfound, wxBITMAP_TYPE_PNG );
    m_bitmapHhsno->SetBitmap( bmp );

    // 本処理
    m_listCtrlView->DeleteAllItems();
    m_imageList->RemoveAll();
    wxListItem item;
    m_textCtrlGuess->SetBackgroundColour(*wxWHITE);

    wxProgressDialog pd( wxT("進行状況"), wxT("処理開始..."), 7, this, wxPD_APP_MODAL|wxPD_REMAINING_TIME|wxPD_AUTO_HIDE );
    pd.SetSize( wxSize(320,140) );

    wxArrayString keys;
    for ( CacheHash::iterator it=CH.begin(); it != CH.end(); ++it ) {
        keys.Add(it->first);
    }
    keys.Sort();
    // イメージリストを作成
    for ( int i=0; i<keys.GetCount(); i++ ) { // item image
        CacheItem* ci = new CacheItem;
        ci = CH[keys[i]];
        m_imageList->Add( ci->thumbnail );
    }
    for ( int i=0; i<keys.GetCount(); i++ ) { // item selected image
        CacheItem* ci = new CacheItem;
        ci = CH[keys[i]];
        m_imageList->Add( ci->selthumbnail );
    }
    // アイテム作成
    bool select = true;  // flag
    for ( int i=0; i<keys.GetCount(); i++ ) {
        CacheItem* ci = new CacheItem;
        ci = CH[keys[i]];
        m_listCtrlView->InsertItem( i, ci->filename, i );
        m_listCtrlView->SetItem( i, 0, ci->filename, i );

        if ( i == 0 ) { // 1枚目はマークシートのはず
            wxImage marksheet( ci->fullpath, wxBITMAP_TYPE_JPEG );

            // 氏名画像を表示
            wxImage name_image;
            name_image  = marksheet.GetSubImage( wxRect( wxPoint(300,550), wxSize(640,190) ) );
            wxBitmap name_bmp  = ( name_image.Scale( LOGO_W, LOGO_H, wxIMAGE_QUALITY_HIGH ) );
            m_bitmapName->SetBitmap( name_bmp );

            // 被保険者番号画像を表示
            wxImage hhsno_image;
            hhsno_image = marksheet.GetSubImage( wxRect( wxPoint(1800,210), wxSize(594,100) ) );
            wxBitmap hhsno_bmp = ( hhsno_image.Scale( HHSN_W, HHSN_H, wxIMAGE_QUALITY_HIGH ) );
            m_bitmapHhsno->SetBitmap( hhsno_bmp );

            wxString hhsno = GuessHhs( ci->fullpath );
            m_textCtrlGuess->SetValue( hhsno );
            wxString name;
            int judge = IsHhsno( hhsno, name );
	        if (      judge == 0 )  m_textCtrlGuess->SetBackgroundColour(*wxRED);       // not hhsno-style
            else if ( judge == 1 )  m_textCtrlGuess->SetBackgroundColour(wxT("YELLOW"));    // not in DB
            m_textCtrlName->SetValue( name );

            SetStatusText( wxString::Format(wxT("1st image : z = %f, l = %d"),ci->z,ci->l), 1 );
            m_listCtrlView->SetItemState( i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
        }
        else {  // 2枚目以降で初めてマークシートを認識したら,それ以降は選択しない
            if ( ci->marksheet ) select = false;
            if ( select ) m_listCtrlView->SetItemState( i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
        }

        pd.Update( i+1, wxT("画像認識中") );
    }

    // 選択したものは青い画像を使う
    long i = -1;
    for ( ;; ) {
        i = m_listCtrlView->GetNextItem(i, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
        if ( i == -1 ) break;
        m_listCtrlView->SetItemImage( i, i+m_listCtrlView->GetItemCount() );
    }

    SetStatusText( wxEmptyString, 2 );
}

/* 画像を選択したとき画像の情報をステータスバーに表示 */
void MyFrame::OnItemSelected(wxListEvent& event)
{
    int i = event.GetIndex();
    m_listCtrlView->SetItemImage( i, i+m_listCtrlView->GetItemCount() );    // 青い画像

    if ( m_listCtrlView->GetSelectedItemCount() != 1 ) return;
    SetStatusText( wxEmptyString, 2 );

    wxString filename = event.GetText();
    CacheItem* ci = new CacheItem;
    ci = CH[filename];
    wxString msg;
    if ( ci->marksheet ) msg = wxT("perhaps marksheet !");
    SetStatusText( wxString::Format(wxT("selected image : z = %f, l = %d ...")+msg, ci->z, ci->l ), 2 );
}
void MyFrame::OnItemDeselected(wxListEvent& event)
{
    int i = event.GetIndex();
    m_listCtrlView->SetItemImage( i, i );
}

/* 画像のスクリーン表示*/
void MyFrame::ViewLarge(wxListEvent& event)
{
    int i = event.GetIndex();
    wxListItem item;
    item.SetId(i);

    wxString filename = event.GetText();
    wxString workdir = m_dirPickerWork->GetPath();
    wxString imagefile = workdir + wxFILE_SEP_PATH + filename;

    wxImage image( imagefile, wxBITMAP_TYPE_JPEG );
    wxBitmap bmp( image.Scale( 707, 1000, wxIMAGE_QUALITY_HIGH ) );
    wxSplashScreen* splash = new wxSplashScreen( bmp,
            wxSPLASH_CENTRE_ON_SCREEN|wxSPLASH_TIMEOUT,
            3000, NULL, -1, wxDefaultPosition, wxDefaultSize,
            wxSIMPLE_BORDER|wxSTAY_ON_TOP );
    wxYield();
}

/* パラメータダイアログ */
void MyFrame::OnParam(wxCommandEvent& WXUNUSED(event))
{
    ParamDialog* pd = new ParamDialog( NULL, wxID_ANY, wxT("Setting Parameters") );
    if ( pd->ShowModal() == wxID_OK ) {
        pd->NewParam( wxGetApp().lmin, wxGetApp().lmax, wxGetApp().zmin, wxGetApp().zmax );
    }
    pd->Destroy();
}

/* キャッシュ作成&更新 */
void MyFrame::UpdateCache()
{
    double zmin, zmax; long lmin, lmax;
    wxGetApp().zmin.ToDouble( &zmin );
    wxGetApp().zmax.ToDouble( &zmax );
    wxGetApp().lmin.ToLong( &lmin );
    wxGetApp().lmax.ToLong( &lmax );

    m_buttonDetect->Enable(false);
    wxGetApp().WriteLog( wxT("start updating cache") );
    wxStopWatch sw;
    sw.Start(0);

    /* キャッシュ存在フラグOFF */
    for ( CacheHash::iterator it=CH.begin(); it != CH.end(); ++it ) {
        CacheItem* ci = new CacheItem;
        ci = it->second;
        ci->exists = false;
    }

    wxString workdir = m_dirPickerWork->GetPath();
    wxArrayString filenames;
    wxListItem item;

    /* キャッシュ作成 */
    unsigned int n = wxDir::GetAllFiles( workdir, &filenames, wxT("*.jpg"), wxDIR_FILES );
    for ( int i=0; i<n; i++ ) {
        wxString fullpath = filenames[i];
        wxFileName f( fullpath );
        wxString file = f.GetFullName();

        CacheItem* ci = new CacheItem;
        /* キャッシュ済みのものはスキップ */
        if ( CH.count(file) ) {
            ci = CH[file];
            ci->exists = true;
            continue;
        }
        /* 新しいファイルはキャッシュ */
        //float z; long l; bool m = IsMarksheet( fullpath, &z, &l );
        float z; long l; bool m = IsMarksheet( fullpath, &z, &l, zmin, zmax, lmin, lmax );
        wxImage image( fullpath, wxBITMAP_TYPE_JPEG );
        wxImage thumbnail = image.Scale( THUMB_W, THUMB_H, wxIMAGE_QUALITY_HIGH );
        wxBitmap bmp( thumbnail );
        unsigned char *data = thumbnail.GetData();
        for ( int y=0; y<THUMB_H; y++ ) for ( int x=0; x<THUMB_W; x++ ) data[(y*THUMB_W+x)*3+2] = 255;  // 文字色:黒(0,0,0)->青(0,0.255)
        wxBitmap bmp_mask( thumbnail );

        ci->filename     = file;
        ci->fullpath     = fullpath;
        ci->marksheet    = m;
        ci->z            = z;
        ci->l            = l;
        ci->exists       = true;
        ci->thumbnail    = bmp;
        ci->selthumbnail = bmp_mask;
        ci->modtime      = wxEmptyString; // TODO.

        CH[ci->filename] = ci;  // add hash
        SetStatusText( wxString::Format( wxT("rebuiling cache...( %d/%d :%.1fsec passed )"), i+1, n, (float)sw.Time()/1000 ), 0 );
        wxGetApp().WriteLog( file + wxT(" appended.") + wxString::Format(wxT(" ( m=%d z=%f l=%d )"), m ? 1 : 0, z, l ) );
    }

    /* 存在しないファイルはキャッシュから削除 */
    wxArrayString removelist;
    for ( CacheHash::iterator it=CH.begin(); it != CH.end(); ++it ) {
        CacheItem* ci = new CacheItem;
        ci = it->second;
        if ( !ci->exists ) removelist.Add( ci->filename );
    }
    for ( int i=0; i<removelist.GetCount(); i++ ) {
        CH.erase(removelist[i]);
        wxGetApp().WriteLog( removelist[i] + wxT(" removed.") );
    }

    m_buttonDetect->Enable(true);
    SetStatusText( wxEmptyString, 0 );
    m_timer.Start( 20*1000, wxTIMER_ONE_SHOT ); // restart
}

/* 被保険者フォルダを列挙 */
void MyFrame::ListHhsDir()
{
    wxString distdir = m_textCtrlDist->GetValue();
    wxString hhsdir;
    wxString buf;

    m_listCtrlHhsDir->DeleteAllItems();
    for ( int i=0; i<m_hhsList.GetCount(); i++ ) {
        hhsdir = distdir + wxFILE_SEP_PATH + m_hhsList[i];
        wxArrayString filenames;
        unsigned int n = wxDir::GetAllFiles( hhsdir, &filenames, wxT("*.jpg"), wxDIR_FILES );

        m_listCtrlHhsDir->InsertItem( i, -1 );
        buf.Printf(wxT("%d"),i+1);
        m_listCtrlHhsDir->SetItem( i, 0, buf, -1 );
        m_listCtrlHhsDir->SetItem( i, 1, m_hhsList[i], -1 );
        buf.Printf(wxT("%d"),n);
        m_listCtrlHhsDir->SetItem( i, 2, buf, -1 );
        if ( i % 2 ) m_listCtrlHhsDir->SetItemBackgroundColour( i, wxColour(wxT("WHEAT")) );
    }
}

/* 被保険者フォルダを開く */
void MyFrame::OnOpenHhsDir(wxListEvent& event)
{
    wxString hhsdir;
    hhsdir.Append( m_textCtrlDist->GetValue() );
    hhsdir.Append( wxFILE_SEP_PATH );

    int i = event.GetIndex();
    wxListItem item;
    item.SetId(i);

    item.SetColumn(1);
    item.SetMask(wxLIST_MASK_TEXT);
    m_listCtrlHhsDir->GetItem( item );
    hhsdir.Append( item.GetText() );
    wxString execmd = wxT("explorer ") + hhsdir;
    wxExecute( execmd );
}

// 以下,定型もの
void MyFrame::OnTimer(wxTimerEvent& event)
{
    UpdateCache();
}

/* キーハンドリング */
void MyFrame::OnChar(wxKeyEvent& event)
{
    if ( event.GetKeyCode() == WXK_F5 ) F5_Shortcut();
    if ( event.GetKeyCode() == WXK_F7 ) F7_Shortcut();
}
void MyFrame::F5_Shortcut()
{
    UpdateCache();
    UpdateListImage();
}
void MyFrame::F7_Shortcut()
{
    MoveImages();
    UpdateCache();
    UpdateListImage();
    ListHhsDir();
    m_buttonUndo->Enable(true);
}

/* アイドリング */
void MyFrame::OnIdle(wxIdleEvent& event)
{
    if ( !m_timer.IsRunning() ) {
        m_timer.Start( 20*1000, wxTIMER_ONE_SHOT );
    }
    event.RequestMore();
    event.Skip();
}

/* アプリフォルダを開く */
void MyFrame::OnOpenAppDir(wxCommandEvent& WXUNUSED(event))
{
    wxString appdir = wxGetCwd();
    wxString execmd = wxT("explorer ") + appdir;
    wxExecute( execmd );
}

/* サイズ変更 */
void MyFrame::OnWinSize(wxSizeEvent& event)
{
    this->Refresh( true, NULL );
    TellLocation();
    event.Skip();
}
/* ウィンドウ移動 */
void MyFrame::OnWinMove(wxMoveEvent& WXUNUSED(event))
{
    TellLocation();
    return;
}
/* ウィンドウ位置とサイズを表示 */
void MyFrame::TellLocation( void ) 
{
    wxRect r = this->GetRect();
    int x = r.GetX();
    int y = r.GetY();
    int w = r.GetWidth();
    int h = r.GetHeight();
    SetStatusText( wxString::Format(wxT("(%d,%d) %dx%d"),x,y,w,h), 3 );
}
/* 終了 */
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    Close(true);
}
/* 設定を保存 */
void MyFrame::SaveConfig(wxCloseEvent& WXUNUSED(event))
{
    if ( !IsIconized() && !IsMaximized() ) {
        wxGetApp().rect = this->GetRect();
    }
    wxGetApp().workdir = m_dirPickerWork->GetPath();

    Destroy();
}