/* 前を検索 */ void CViewCommander::Command_SEARCH_PREV( bool bReDraw, HWND hwndParent ) { if( L'\0' == GetDllShareData().m_sSearchKeywords.m_aSearchKeys[0][0] ){ return; // 検索文字列が空だった。 } // マッチ結果で選択範囲を置き換えるか、既存の範囲を拡張(縮小)するか。 const bool keepCurrentSelection = m_pCommanderView->GetSelectionInfo().IsTextSelected() && m_pCommanderView->GetSelectionInfo().m_bSelectingLock && ! m_pCommanderView->GetSelectionInfo().IsBoxSelecting(); // 検索開始位置( searchPos )をキャレットの位置から決定する。 struct SearchPos { CLayoutInt y; // レイアウト行 CLogicInt x; // レイアウト行内での文字(wchar_t)単位でのオフセット。 } searchPos; const CLayoutPoint& caretPos = GetCaret().GetCaretLayoutPos(); const CLayout* pLayout = GetDocument()->m_cLayoutMgr.SearchLineByLayoutY( caretPos.y ); if( pLayout ) { searchPos.y = caretPos.y; searchPos.x = m_pCommanderView->LineColmnToIndex( pLayout, caretPos.x ); } else if( 0 < caretPos.y ) { // pLayoutが NULLとなるのは、[EOF]から前検索した場合。1行前の行末からの検索にする。 const CLayoutInt y = std::min( caretPos.y - 1, GetDocument()->m_cLayoutMgr.GetLineCount() - 1 ); pLayout = GetDocument()->m_cLayoutMgr.SearchLineByLayoutY( y ); if( pLayout ) { searchPos.y = y; searchPos.x = pLayout->GetLengthWithoutEOL() + pLayout->GetLayoutEol().GetLen(); } } // 2002.01.16 hor if( ! m_pCommanderView->ChangeCurRegexp() ) { return; // パターン検索だったが正規表現ライブラリが利用可能でなかった。 } /* 検索開始位置より前を検索する */ bool found = false; CLayoutRange matchLayoutRange = CLayoutRange( CLayoutPoint( -1, -1 ), CLayoutPoint( -1, -1 ) ); const SearchPos originalSearchPos = searchPos; if( pLayout ) { bool retried = false; ///< 末尾から再検索したかどうか。 for(;;) { found = 0 != GetDocument()->m_cLayoutMgr.SearchWord( searchPos.y, searchPos.x, m_pCommanderView->m_szCurSrchKey, // 検索語 SEARCH_BACKWARD, m_pCommanderView->m_sCurSearchOption, // 検索オプション &matchLayoutRange, // マッチレイアウト範囲 &m_pCommanderView->m_CurRegexp // 正規表現コンパイルデータ ); if( ! found && GetDllShareData().m_Common.m_sSearch.m_bSearchAll && ! retried ) { // From Here 2002.01.26 hor 見つからなかったので末尾から再検索する。 searchPos.y = GetDocument()->m_cLayoutMgr.GetLineCount() - 1; searchPos.x = static_cast( MAXLINEKETAS ); // とにかく大きければよい。 retried = true; continue; } if( found ) { CLogicRange matchLogicRange; this->GetDocument()->m_cLayoutMgr.LayoutToLogic( matchLayoutRange, &matchLogicRange ); // 検索開始位置での幅0マッチはなかったことにして一つ前から探す。 if( matchLayoutRange.GetFrom() == matchLayoutRange.GetTo() && matchLayoutRange.GetFrom().y == originalSearchPos.y && matchLogicRange.GetFrom().x == originalSearchPos.x ) { searchPos.x -= 1; found = false; continue; } } break; } } if( found ) { /* 選択範囲の更新 */ if( keepCurrentSelection ) { // マッチの先頭まで範囲を拡大(縮小)する。 m_pCommanderView->GetSelectionInfo().ChangeSelectAreaByCurrentCursor( matchLayoutRange.GetFrom() ); } else { /* マッチ範囲を選択する */ // 2005.06.24 Moca m_pCommanderView->GetSelectionInfo().DisableSelectArea( bReDraw ); m_pCommanderView->GetSelectionInfo().SetSelectArea( matchLayoutRange ); if( bReDraw ){ m_pCommanderView->GetSelectionInfo().DrawSelectArea(); } } /* カーソル移動 */ // Sep. 8, 2000 genta m_pCommanderView->AddCurrentLineToHistory(); GetCaret().MoveCursor( matchLayoutRange.GetFrom(), bReDraw ); GetCaret().m_nCaretPosX_Prev = GetCaret().GetCaretLayoutPos().GetX2(); /* メッセージ */ if( PointCompare( originalSearchPos, searchPos ) > 0 ) { m_pCommanderView->SendStatusMessage(_T("▲末尾から再検索しました")); } } else { /* フォーカス移動時の再描画 */ // m_pCommanderView->RedrawAll(); hor コメント化 /* 選択範囲の更新 */ if( keepCurrentSelection ) { // 変更しない。 } else { // キャンセル。 if( m_pCommanderView->GetSelectionInfo().IsTextSelected() ) { m_pCommanderView->GetSelectionInfo().DisableSelectArea( bReDraw ); } } /* メッセージ */ m_pCommanderView->SendStatusMessage(_T("△見つかりませんでした")); ErrorBeep(); // To Here 2002.01.26 hor if( bReDraw && GetDllShareData().m_Common.m_sSearch.m_bNOTIFYNOTFOUND ) { /* 検索/置換 見つからないときメッセージを表示 */ InfoMessage( hwndParent ? hwndParent : m_pCommanderView->GetHwnd(), _T("前方(↑) に文字列 '%ls' が1つも見つかりません。"), //Jan. 25, 2001 jepro メッセージを若干変更 m_pCommanderView->m_szCurSrchKey ); } } } /*! 次を検索 @param bChangeCurRegexp 共有データの検索文字列を使う @date 2003.05.22 かろと 無限マッチ対策.行頭・行末処理見直し. @date 2004.05.30 Moca bChangeCurRegexp=trueで従来通り。falseで、CEditViewの現在設定されている検索パターンを使う */ void CViewCommander::Command_SEARCH_NEXT( const bool bChangeCurRegexp, const bool bRedraw, const HWND hwndParent, const WCHAR* const pszNotFoundMessage ) { // 2004.05.30 Moca bChangeCurRegexpに応じて対象文字列を変える if( bChangeCurRegexp ) { if( ! GetDllShareData().m_sSearchKeywords.m_aSearchKeys[0][0] ) { return; // 検索語が空だった。 } // 2002.01.16 hor // 共通部分のくくりだし // 2004.05.30 Moca CEditViewの現在設定されている検索パターンを使えるように if( ! m_pCommanderView->ChangeCurRegexp() ) { return; // パターン検索だったが正規表現ライブラリが利用可能でなかった。 } } else { if( ! m_pCommanderView->m_szCurSrchKey[0] ) { return; // 検索語が空だった。 } } // 以後、検索条件は m_pCommanderView->m_szCurSrchKey (検索語)と // m_pCommanderView->m_sCurSearchOption (検索オプション)と // m_pCommanderView->m_CurRegexp (コンパイル済み検索語)から手に入る。 CViewSelect& sel = m_pCommanderView->GetSelectionInfo(); // 長いのでショートカット。 // マッチ結果で選択範囲を置き換えるか、既存の範囲を拡張(縮小)するか。 const bool keepCurrentSelection = sel.IsTextSelected() && sel.m_bSelectingLock && ! sel.IsBoxSelecting(); const bool selectingBackward = sel.IsTextSelected() && PointCompare( sel.m_sSelectBgn.GetFrom(), sel.m_sSelect.GetFrom() ) > 0; // 検索開始位置( searchPos )をキャレットの位置と選択範囲から決定する。 struct SearchPos { CLayoutInt y; // レイアウト行 CLogicInt x; // レイアウト行内での文字(wchar_t)単位でのオフセット。 } searchPos; const CLayoutPoint searchLayoutPos = // 選択範囲の左端(たぶんキャレットもそこにある)が選択始点より前にあるなら、 // 選択範囲の左端が検索開始点。もし検索開始点でマッチしたときは // 選択範囲が変わらないために、検索をやり直す必要があることに注意。 keepCurrentSelection && selectingBackward ? sel.m_sSelect.GetFrom() : // 通常は、選択範囲の右端かキャレットの位置から検索する。 sel.IsTextSelected() ? sel.m_sSelect.GetTo() : GetCaret().GetCaretLayoutPos(); const CLayout* const pLayout = GetDocument()->m_cLayoutMgr.SearchLineByLayoutY( searchLayoutPos.y ); searchPos.y = searchLayoutPos.y; searchPos.x = pLayout ? m_pCommanderView->LineColmnToIndex( pLayout, searchLayoutPos.x ) : CLogicInt(0); /* 検索開始位置より後ろを検索する */ // 2004.05.30 Moca 引数をGetShareData()からメンバ変数に変更。他のプロセス/スレッドに書き換えられてしまわないように。 bool found = false; CLayoutRange matchLayoutRange; //sRangeA.Set(GetCaret().GetCaretLayoutPos()); const SearchPos originalSearchPos = searchPos; for( bool retried = false/*先頭から再検索したかどうか*/;;) { found = 0 != GetDocument()->m_cLayoutMgr.SearchWord( searchPos.y, // 検索開始レイアウト行 searchPos.x, // 検索開始データ位置 m_pCommanderView->m_szCurSrchKey, // 検索語 SEARCH_FORWARD, m_pCommanderView->m_sCurSearchOption, // 検索オプション &matchLayoutRange, &m_pCommanderView->m_CurRegexp // 正規表現コンパイルデータ ); if( found ) { CLogicRange matchLogicRange; this->GetDocument()->m_cLayoutMgr.LayoutToLogic( matchLayoutRange, &matchLogicRange ); if( // 検索開始点でマッチしていて、 (matchLayoutRange.GetFrom().y == originalSearchPos.y && matchLogicRange.GetFrom().x == originalSearchPos.x) && // 幅0マッチだったり上方向選択中だったりして、検索前と後で状態が変わらないならば、 (matchLayoutRange.GetFrom() == matchLayoutRange.GetTo() || keepCurrentSelection && selectingBackward) && // 次の文字が存在する限りにおいて pLayout ) { // やり直す。 searchPos.x += std::max( CLogicInt(1), CNativeW::GetSizeOfChar( pLayout->GetPtr(), pLayout->GetLengthWithoutEOL() + pLayout->GetLayoutEol().GetLen(), originalSearchPos.x ) ); found = false; continue; } } if( ! found && GetDllShareData().m_Common.m_sSearch.m_bSearchAll && ! retried ) { // 見つからなかったので先頭から再検索する。 searchPos.y = CLayoutInt(0); searchPos.x = CLogicInt(0); retried = true; continue; } break; } if( found ) { /* 選択範囲の変更*/ if( keepCurrentSelection ) { // 検索結果により選択範囲を拡縮する。 sel.ChangeSelectAreaByCurrentCursor( // マッチ結果の両端のうち、選択始点より遠い方を利用する。 PointCompare( sel.m_sSelectBgn.GetFrom(), matchLayoutRange.GetFrom() ) > 0 ? matchLayoutRange.GetFrom() // 選択始点よりマッチ始点が前にある場合。 : matchLayoutRange.GetTo() ); } else { // マッチ範囲で選択範囲を置き換える。 sel.DisableSelectArea( bRedraw ); sel.SetSelectArea( matchLayoutRange ); if( bRedraw ){ /* 選択領域描画 */ sel.DrawSelectArea(); } } /* カーソル移動 */ // Sep. 8, 2000 genta if ( m_pCommanderView->GetDrawSwitch() ) m_pCommanderView->AddCurrentLineToHistory(); // 2002.02.16 hor すべて置換のときは不要 GetCaret().MoveCursor( matchLayoutRange.GetFrom(), bRedraw ); GetCaret().m_nCaretPosX_Prev = GetCaret().GetCaretLayoutPos().GetX2(); /* メッセージ */ if( PointCompare( originalSearchPos, searchPos ) > 0 ) { m_pCommanderView->SendStatusMessage(_T("▼先頭から再検索しました")); } } else { /* 選択範囲の変更*/ if( keepCurrentSelection ) { // 検索結果により選択範囲を拡縮する。 // つまり、何もしない。 } else { // マッチ範囲で選択範囲を置き換える。 // つまり、選択をキャンセルする。 sel.DisableSelectArea( bRedraw ); } GetCaret().ShowEditCaret(); // 2002/04/18 YAZAKI GetCaret().ShowCaretPosInfo(); // 2002/04/18 YAZAKI /* メッセージ */ m_pCommanderView->SendStatusMessage(_T("▽見つかりませんでした")); ErrorBeep(); if( bRedraw && GetDllShareData().m_Common.m_sSearch.m_bNOTIFYNOTFOUND ) { InfoMessage( hwndParent ? hwndParent : m_pCommanderView->GetHwnd(), pszNotFoundMessage ? _T("%ls") : _T("後方(↓) に文字列 '%ls' が1つも見つかりません。"), pszNotFoundMessage ? pszNotFoundMessage : m_pCommanderView->m_szCurSrchKey ); } } }